Merge "Add @PromotedNotificationLog" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6e37b7e..6393fdb 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -112,6 +112,7 @@
         "framework_graphics_flags_java_lib",
         "hwui_flags_java_lib",
         "interaction_jank_monitor_flags_lib",
+        "keystore2_flags_java-framework",
         "libcore_exported_aconfig_flags_lib",
         "libcore_readonly_aconfig_flags_lib",
         "libgui_flags_java_lib",
diff --git a/Android.bp b/Android.bp
index 48f0928..54cb268 100644
--- a/Android.bp
+++ b/Android.bp
@@ -107,7 +107,6 @@
         ":android.hardware.radio.data-V3-java-source",
         ":android.hardware.radio.network-V3-java-source",
         ":android.hardware.radio.voice-V3-java-source",
-        ":android.hardware.security.keymint-V3-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
         ":android.hardware.thermal-V3-java-source",
         ":android.hardware.tv.tuner-V3-java-source",
@@ -116,7 +115,6 @@
         ":android.security.legacykeystore-java-source",
         ":android.security.maintenance-java-source",
         ":android.security.metrics-java-source",
-        ":android.system.keystore2-V4-java-source",
         ":android.hardware.cas-V1-java-source",
         ":credstore_aidl",
         ":dumpstate_aidl",
@@ -149,7 +147,16 @@
         ":statslog-framework-java-gen", // FrameworkStatsLog.java
         ":statslog-hwui-java-gen", // HwuiStatsLog.java
         ":audio_policy_configuration_V7_0",
-    ],
+    ] + select(release_flag("RELEASE_ATTEST_MODULES"), {
+        true: [
+            ":android.hardware.security.keymint-V4-java-source",
+            ":android.system.keystore2-V5-java-source",
+        ],
+        default: [
+            ":android.hardware.security.keymint-V3-java-source",
+            ":android.system.keystore2-V4-java-source",
+        ],
+    }),
 }
 
 java_library {
@@ -398,6 +405,7 @@
         "bouncycastle-repackaged-unbundled",
         "com.android.sysprop.foldlockbehavior",
         "com.android.sysprop.view",
+        "configinfra_framework_flags_java_lib",
         "framework-internal-utils",
         "dynamic_instrumentation_manager_aidl-java",
         // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
diff --git a/FF_LEADS_OWNERS b/FF_LEADS_OWNERS
new file mode 100644
index 0000000..a650c6b
--- /dev/null
+++ b/FF_LEADS_OWNERS
@@ -0,0 +1,10 @@
+bills@google.com
+carmenjackson@google.com
+nalini@google.com
+nosh@google.com
+olilan@google.com
+philipcuadra@google.com
+rajekumar@google.com
+shayba@google.com
+timmurray@google.com
+zezeozue@google.com
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index e9357f4..1175677 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 package {
-    default_team: "trendy_team_input_framework",
+    default_team: "trendy_team_windowing_animations_transitions",
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
     // all of the 'license_kinds' from "frameworks_base_license"
diff --git a/apex/jobscheduler/service/aconfig/alarm.aconfig b/apex/jobscheduler/service/aconfig/alarm.aconfig
index d3068d7..a6e9807 100644
--- a/apex/jobscheduler/service/aconfig/alarm.aconfig
+++ b/apex/jobscheduler/service/aconfig/alarm.aconfig
@@ -2,16 +2,6 @@
 container: "system"
 
 flag {
-    name: "use_frozen_state_to_drop_listener_alarms"
-    namespace: "backstage_power"
-    description: "Use frozen state callback to drop listener alarms for cached apps"
-    bug: "324470945"
-    metadata {
-      purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
     name: "start_user_before_scheduled_alarms"
     namespace: "multiuser"
     description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due"
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 033da2d..60ba3b8 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -282,7 +282,6 @@
 
     private final Injector mInjector;
     int mBroadcastRefCount = 0;
-    boolean mUseFrozenStateToDropListenerAlarms;
     MetricsHelper mMetricsHelper;
     PowerManager.WakeLock mWakeLock;
     SparseIntArray mAlarmsPerUid = new SparseIntArray();
@@ -1784,40 +1783,37 @@
         mMetricsHelper = new MetricsHelper(getContext(), mLock);
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
 
-        mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms();
         mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms()
                 && UserManager.supportsMultipleUsers();
         if (mStartUserBeforeScheduledAlarms) {
             mUserWakeupStore = new UserWakeupStore();
             mUserWakeupStore.init();
         }
-        if (mUseFrozenStateToDropListenerAlarms) {
-            final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> {
-                final int size = frozenStates.length;
-                if (uids.length != size) {
-                    Slog.wtf(TAG, "Got different length arrays in frozen state callback!"
-                            + " uids.length: " + uids.length + " frozenStates.length: " + size);
-                    // Cannot process received data in any meaningful way.
-                    return;
+        final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> {
+            final int size = frozenStates.length;
+            if (uids.length != size) {
+                Slog.wtf(TAG, "Got different length arrays in frozen state callback!"
+                        + " uids.length: " + uids.length + " frozenStates.length: " + size);
+                // Cannot process received data in any meaningful way.
+                return;
+            }
+            final IntArray affectedUids = new IntArray();
+            for (int i = 0; i < size; i++) {
+                if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) {
+                    continue;
                 }
-                final IntArray affectedUids = new IntArray();
-                for (int i = 0; i < size; i++) {
-                    if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) {
-                        continue;
-                    }
-                    if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED,
-                            uids[i])) {
-                        continue;
-                    }
-                    affectedUids.add(uids[i]);
+                if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED,
+                        uids[i])) {
+                    continue;
                 }
-                if (affectedUids.size() > 0) {
-                    removeExactListenerAlarms(affectedUids.toArray());
-                }
-            };
-            final ActivityManager am = getContext().getSystemService(ActivityManager.class);
-            am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback);
-        }
+                affectedUids.add(uids[i]);
+            }
+            if (affectedUids.size() > 0) {
+                removeExactListenerAlarms(affectedUids.toArray());
+            }
+        };
+        final ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback);
 
         mListenerDeathRecipient = new IBinder.DeathRecipient() {
             @Override
@@ -2994,13 +2990,10 @@
 
             pw.println("Feature Flags:");
             pw.increaseIndent();
-            pw.print(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS,
-                    mUseFrozenStateToDropListenerAlarms);
-            pw.println();
             pw.print(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS,
                     Flags.startUserBeforeScheduledAlarms());
-            pw.decreaseIndent();
             pw.println();
+            pw.decreaseIndent();
             pw.println();
 
             pw.println("App Standby Parole: " + mAppStandbyParole);
@@ -5146,38 +5139,6 @@
                 removeForStoppedLocked(uid);
             }
         }
-
-        @Override
-        public void handleUidCachedChanged(int uid, boolean cached) {
-            if (mUseFrozenStateToDropListenerAlarms) {
-                // Use ActivityManager#UidFrozenStateChangedCallback instead.
-                return;
-            }
-            if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) {
-                return;
-            }
-            // Apps can quickly get frozen after being cached, breaking the exactness guarantee on
-            // listener alarms. So going forward, the contract of exact listener alarms explicitly
-            // states that they will be removed as soon as the app goes out of lifecycle. We still
-            // allow a short grace period for quick shuffling of proc-states that may happen
-            // unexpectedly when switching between different lifecycles and is generally hard for
-            // apps to avoid.
-
-            final long delay;
-            synchronized (mLock) {
-                delay = mConstants.CACHED_LISTENER_REMOVAL_DELAY;
-            }
-            final Integer uidObj = uid;
-
-            if (cached && !mHandler.hasEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED,
-                    uidObj)) {
-                mHandler.sendMessageDelayed(
-                        mHandler.obtainMessage(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj),
-                        delay);
-            } else {
-                mHandler.removeEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj);
-            }
-        }
     };
 
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index 1ebe0cd..89351fd 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -61,6 +61,7 @@
         ":framework-bluetooth-sources",
         ":framework-connectivity-tiramisu-updatable-sources",
         ":framework-graphics-srcs",
+        ":framework-healthfitness-sources",
         ":framework-mediaprovider-sources",
         ":framework-nearby-sources",
         ":framework-nfc-updatable-sources",
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index f726361..a88796c3 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -217,6 +217,9 @@
         serializer.attribute("", "selected", Boolean.toString(node.isSelected()));
         serializer.attribute("", "bounds", AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(
                 node, width, height).toShortString());
+        serializer.attribute("", "drawing-order", Integer.toString(node.getDrawingOrder()));
+        serializer.attribute("", "hint", safeCharSeqToString(node.getHintText()));
+
         int count = node.getChildCount();
         for (int i = 0; i < count; i++) {
             AccessibilityNodeInfo child = node.getChild(i);
diff --git a/core/api/current.txt b/core/api/current.txt
index dc7ccd4..a03f8c5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -23,6 +23,7 @@
     field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
     field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
     field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+    field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String APPLY_PICTURE_PROFILE = "android.permission.APPLY_PICTURE_PROFILE";
     field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -336,7 +337,7 @@
     field public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
     field public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
     field public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
-    field @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES";
+    field @FlaggedApi("com.android.settingslib.flags.write_system_preference_permission_enabled") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES";
     field public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
   }
 
@@ -1276,6 +1277,7 @@
     field public static final int paddingStart = 16843699; // 0x10103b3
     field public static final int paddingTop = 16842967; // 0x10100d7
     field public static final int paddingVertical = 16844094; // 0x101053e
+    field @FlaggedApi("android.content.pm.app_compat_option_16kb") public static final int pageSizeCompat;
     field public static final int panelBackground = 16842846; // 0x101005e
     field public static final int panelColorBackground = 16842849; // 0x1010061
     field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -2043,6 +2045,12 @@
     field public static final int system_error_container_light = 17170554; // 0x106007a
     field public static final int system_error_dark = 17170595; // 0x10600a3
     field public static final int system_error_light = 17170552; // 0x1060078
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_light;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_light;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_light;
     field public static final int system_neutral1_0 = 17170461; // 0x106001d
     field public static final int system_neutral1_10 = 17170462; // 0x106001e
     field public static final int system_neutral1_100 = 17170464; // 0x1060020
@@ -2119,12 +2127,16 @@
     field public static final int system_primary_fixed = 17170612; // 0x10600b4
     field public static final int system_primary_fixed_dim = 17170613; // 0x10600b5
     field public static final int system_primary_light = 17170528; // 0x1060060
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_light;
     field public static final int system_secondary_container_dark = 17170573; // 0x106008d
     field public static final int system_secondary_container_light = 17170530; // 0x1060062
     field public static final int system_secondary_dark = 17170575; // 0x106008f
     field public static final int system_secondary_fixed = 17170616; // 0x10600b8
     field public static final int system_secondary_fixed_dim = 17170617; // 0x10600b9
     field public static final int system_secondary_light = 17170532; // 0x1060064
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_light;
     field public static final int system_surface_bright_dark = 17170590; // 0x106009e
     field public static final int system_surface_bright_light = 17170547; // 0x1060073
     field public static final int system_surface_container_dark = 17170587; // 0x106009b
@@ -2142,6 +2154,8 @@
     field public static final int system_surface_dim_light = 17170548; // 0x1060074
     field public static final int system_surface_disabled = 17170626; // 0x10600c2
     field public static final int system_surface_light = 17170540; // 0x106006c
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_dark;
+    field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_light;
     field public static final int system_surface_variant_dark = 17170592; // 0x10600a0
     field public static final int system_surface_variant_light = 17170549; // 0x1060075
     field public static final int system_tertiary_container_dark = 17170577; // 0x1060091
@@ -8075,6 +8089,7 @@
     method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
     method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@Nullable android.content.ComponentName);
+    method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimePolicy();
     method @Deprecated public boolean getAutoTimeRequired();
     method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeZoneEnabled(@Nullable android.content.ComponentName);
     method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimeZonePolicy();
@@ -8233,6 +8248,7 @@
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimeEnabled(@Nullable android.content.ComponentName, boolean);
+    method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimePolicy(int);
     method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
     method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@Nullable android.content.ComponentName, boolean);
     method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZonePolicy(int);
@@ -8354,6 +8370,9 @@
     field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+    field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_DISABLED = 1; // 0x1
+    field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_ENABLED = 2; // 0x2
+    field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
     field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_DISABLED = 1; // 0x1
     field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_ENABLED = 2; // 0x2
     field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
@@ -13562,6 +13581,7 @@
     field public static final String PROPERTY_MEDIA_CAPABILITIES = "android.media.PROPERTY_MEDIA_CAPABILITIES";
     field public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES = "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES";
     field public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE";
+    field @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE = "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE";
     field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff
     field public static final int SIGNATURE_MATCH = 0; // 0x0
     field public static final int SIGNATURE_NEITHER_SIGNED = 1; // 0x1
@@ -13798,6 +13818,7 @@
 
   public final class SharedLibraryInfo implements android.os.Parcelable {
     method public int describeContents();
+    method @FlaggedApi("android.content.pm.sdk_dependency_installer") @NonNull public java.util.List<java.lang.String> getCertDigests();
     method @NonNull public android.content.pm.VersionedPackage getDeclaringPackage();
     method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
     method @IntRange(from=0xffffffff) public long getLongVersion();
@@ -17465,6 +17486,7 @@
     method public void setFloatUniform(@NonNull String, @NonNull float[]);
     method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
     method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+    method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
     method public void setIntUniform(@NonNull String, int);
     method public void setIntUniform(@NonNull String, int, int);
     method public void setIntUniform(@NonNull String, int, int, int);
@@ -17483,7 +17505,29 @@
     method public void setFloatUniform(@NonNull String, float, float, float, float);
     method public void setFloatUniform(@NonNull String, @NonNull float[]);
     method public void setInputBuffer(@NonNull String, @NonNull android.graphics.BitmapShader);
+    method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
     method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+    method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
+    method public void setIntUniform(@NonNull String, int);
+    method public void setIntUniform(@NonNull String, int, int);
+    method public void setIntUniform(@NonNull String, int, int, int);
+    method public void setIntUniform(@NonNull String, int, int, int, int);
+    method public void setIntUniform(@NonNull String, @NonNull int[]);
+  }
+
+  @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeXfermode extends android.graphics.Xfermode {
+    ctor public RuntimeXfermode(@NonNull String);
+    method public void setColorUniform(@NonNull String, @ColorInt int);
+    method public void setColorUniform(@NonNull String, @ColorLong long);
+    method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color);
+    method public void setFloatUniform(@NonNull String, float);
+    method public void setFloatUniform(@NonNull String, float, float);
+    method public void setFloatUniform(@NonNull String, float, float, float);
+    method public void setFloatUniform(@NonNull String, float, float, float, float);
+    method public void setFloatUniform(@NonNull String, @NonNull float[]);
+    method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter);
+    method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
+    method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode);
     method public void setIntUniform(@NonNull String, int);
     method public void setIntUniform(@NonNull String, int, int);
     method public void setIntUniform(@NonNull String, int, int, int);
@@ -18821,6 +18865,19 @@
     field public static final int TRANSFER_UNSPECIFIED = 0; // 0x0
   }
 
+  @FlaggedApi("android.hardware.flags.luts_api") public final class DisplayLuts {
+    ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts();
+    method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry);
+    method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry, @NonNull android.hardware.DisplayLuts.Entry);
+  }
+
+  @FlaggedApi("android.hardware.flags.luts_api") public static class DisplayLuts.Entry {
+    ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts.Entry(@NonNull float[], int, int);
+    method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public float[] getBuffer();
+    method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+    method @FlaggedApi("android.hardware.flags.luts_api") public int getSamplingKey();
+  }
+
   public class GeomagneticField {
     ctor public GeomagneticField(float, float, float, long);
     method public float getDeclination();
@@ -18882,8 +18939,19 @@
     field @FlaggedApi("android.media.codec.p210_format_support") public static final int YCBCR_P210 = 60; // 0x3c
   }
 
+  @FlaggedApi("android.hardware.flags.luts_api") public final class LutProperties {
+    method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+    method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys();
+    method @FlaggedApi("android.hardware.flags.luts_api") public int getSize();
+    field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1
+    field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1
+    field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0
+    field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3
+  }
+
   @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public final class OverlayProperties implements android.os.Parcelable {
     method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public int describeContents();
+    method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.hardware.LutProperties[] getLutProperties();
     method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isCombinationSupported(int, int);
     method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isMixedColorSpacesSupported();
     method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -20623,8 +20691,14 @@
     method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionMode();
     method public int getMatchContentFrameRateUserPreference();
     method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
+    method @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public void registerDisplayListener(@NonNull java.util.concurrent.Executor, long, @NonNull android.hardware.display.DisplayManager.DisplayListener);
     method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
     field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+    field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_ADDED = 1L; // 0x1L
+    field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_CHANGED = 4L; // 0x4L
+    field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 8L; // 0x8L
+    field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REMOVED = 2L; // 0x2L
+    field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_STATE = 16L; // 0x10L
     field public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; // 0x2
     field public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; // 0x0
     field public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; // 0x1
@@ -21081,6 +21155,7 @@
     method @Deprecated public android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
     method public android.view.View onCreateInputView();
     method protected void onCurrentInputMethodSubtypeChanged(android.view.inputmethod.InputMethodSubtype);
+    method @FlaggedApi("android.view.inputmethod.ime_switcher_revamp_api") public void onCustomImeSwitcherButtonRequestedVisible(boolean);
     method public void onDisplayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public boolean onEvaluateFullscreenMode();
     method @CallSuper public boolean onEvaluateInputViewShown();
@@ -21482,6 +21557,7 @@
     method public int getId();
     method public CharSequence getProductName();
     method @NonNull public int[] getSampleRates();
+    method @FlaggedApi("android.media.audio.speaker_layout_api") public int getSpeakerLayoutChannelMask();
     method public int getType();
     method public boolean isSink();
     method public boolean isSource();
@@ -21970,7 +22046,7 @@
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioAttributes getAudioAttributes();
-    method @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo();
+    method @Deprecated @FlaggedApi("android.media.audio.routed_device_ids") @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
   }
@@ -22053,6 +22129,7 @@
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public int getRecordingState();
     method public android.media.AudioDeviceInfo getRoutedDevice();
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
     method public int getSampleRate();
     method public int getState();
     method public int getTimestamp(@NonNull android.media.AudioTimestamp, int);
@@ -22147,6 +22224,7 @@
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public default java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
   }
@@ -22205,6 +22283,7 @@
     method public int getPositionNotificationPeriod();
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
     method public int getSampleRate();
     method @IntRange(from=1) public int getStartThresholdInFrames();
     method public int getState();
@@ -24373,6 +24452,7 @@
     method @NonNull public android.media.PlaybackParams getPlaybackParams();
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
     method @NonNull public android.media.SyncParams getSyncParams();
     method @Nullable public android.media.MediaTimestamp getTimestamp();
@@ -24586,6 +24666,7 @@
     method public android.os.PersistableBundle getMetrics();
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices();
     method public android.view.Surface getSurface();
     method public boolean isPrivacySensitive();
     method public void pause() throws java.lang.IllegalStateException;
@@ -28517,6 +28598,8 @@
     method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.ad.TvAdView.TvAdCallback);
     method public void setOnUnhandledInputEventListener(@NonNull android.media.tv.ad.TvAdView.OnUnhandledInputEventListener);
     method public boolean setTvView(@Nullable android.media.tv.TvView);
+    method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderMediaOverlay(boolean);
+    method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderOnTop(boolean);
     method public void startAdService();
     method public void stopAdService();
     field public static final String ERROR_KEY_ERROR_CODE = "error_code";
@@ -28789,6 +28872,8 @@
     method public void setOnUnhandledInputEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener);
     method public void setTeletextAppEnabled(boolean);
     method public int setTvView(@Nullable android.media.tv.TvView);
+    method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderMediaOverlay(boolean);
+    method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderOnTop(boolean);
     method public void startInteractiveApp();
     method public void stopInteractiveApp();
     field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
@@ -29828,6 +29913,7 @@
     method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities();
     method public boolean hasGatewayOption(int);
     method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled();
+    field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff
     field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0
   }
 
@@ -33301,6 +33387,14 @@
     method public final android.os.CountDownTimer start();
   }
 
+  @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams {
+    ctor public CpuHeadroomParams();
+    method public int getCalculationType();
+    method public void setCalculationType(int);
+    field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
+    field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
+  }
+
   public final class CpuUsageInfo implements android.os.Parcelable {
     method public int describeContents();
     method public long getActive();
@@ -33548,6 +33642,14 @@
     method public void onProgress(long);
   }
 
+  @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams {
+    ctor public GpuHeadroomParams();
+    method public int getCalculationType();
+    method public void setCalculationType(int);
+    field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1
+    field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0
+  }
+
   public class Handler {
     ctor @Deprecated public Handler();
     ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback);
@@ -34648,8 +34750,6 @@
     method public static android.os.VibrationEffect createWaveform(long[], int[], int);
     method public int describeContents();
     method @NonNull public static android.os.VibrationEffect.Composition startComposition();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(@FloatRange(from=0) float);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
     field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
     field public static final int EFFECT_CLICK = 0; // 0x0
@@ -34662,7 +34762,10 @@
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int);
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float);
     method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int);
+    method @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int, int);
     method @NonNull public android.os.VibrationEffect compose();
+    field @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") public static final int DELAY_TYPE_PAUSE = 0; // 0x0
+    field @FlaggedApi("android.os.vibrator.primitive_composition_absolute_delay") public static final int DELAY_TYPE_RELATIVE_START_OFFSET = 1; // 0x1
     field public static final int PRIMITIVE_CLICK = 1; // 0x1
     field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8
     field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6
@@ -34674,8 +34777,10 @@
   }
 
   @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.WaveformEnvelopeBuilder {
+    ctor public VibrationEffect.WaveformEnvelopeBuilder();
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, int);
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder setInitialFrequencyHz(@FloatRange(from=0) float);
   }
 
   public abstract class Vibrator {
@@ -34685,12 +34790,9 @@
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public boolean areEnvelopeEffectsSupported();
     method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
     method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
+    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.vibrator.VibratorEnvelopeEffectInfo getEnvelopeEffectInfo();
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.os.vibrator.VibratorFrequencyProfile getFrequencyProfile();
     method public int getId();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectControlPointDurationMillis();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectDurationMillis();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectSize();
-    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMinEnvelopeEffectControlPointDurationMillis();
     method @NonNull public int[] getPrimitiveDurations(@NonNull int...);
     method public float getQFactor();
     method public float getResonantFrequency();
@@ -34798,6 +34900,10 @@
   }
 
   public class SystemHealthManager {
+    method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getCpuHeadroom(@Nullable android.os.CpuHeadroomParams);
+    method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getCpuHeadroomMinIntervalMillis();
+    method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getGpuHeadroom(@Nullable android.os.GpuHeadroomParams);
+    method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getGpuHeadroomMinIntervalMillis();
     method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.PowerMonitorReadings,java.lang.RuntimeException>);
     method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>);
     method public android.os.health.HealthStats takeMyUidSnapshot();
@@ -35041,6 +35147,16 @@
 
 package android.os.vibrator {
 
+  @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class VibratorEnvelopeEffectInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getMaxControlPointDurationMillis();
+    method public long getMaxDurationMillis();
+    method public int getMaxSize();
+    method public long getMinControlPointDurationMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.vibrator.VibratorEnvelopeEffectInfo> CREATOR;
+  }
+
   @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public final class VibratorFrequencyProfile {
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.util.SparseArray<java.lang.Float> getFrequenciesOutputAcceleration();
     method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @Nullable public android.util.Range<java.lang.Float> getFrequencyRange(float);
@@ -40659,6 +40775,7 @@
     method public int describeContents();
     method @Deprecated @Nullable public android.os.Bundle getClientState();
     method @Nullable public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
   }
@@ -40668,10 +40785,12 @@
     method @Nullable public android.os.Bundle getClientState();
     method @Nullable public String getDatasetId();
     method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") @Nullable public android.view.autofill.AutofillId getFocusedId();
     method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds();
     method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField();
     method public int getNoSaveUiReason();
     method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") @NonNull public java.util.Set<java.lang.String> getShownDatasetIds();
     method public int getType();
     method public int getUiType();
     field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6
@@ -40680,6 +40799,7 @@
     field public static final int NO_SAVE_UI_REASON_NONE = 0; // 0x0
     field public static final int NO_SAVE_UI_REASON_NO_SAVE_INFO = 1; // 0x1
     field public static final int NO_SAVE_UI_REASON_NO_VALUE_CHANGED = 4; // 0x4
+    field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7; // 0x7
     field public static final int NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG = 2; // 0x2
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
     field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
@@ -40688,6 +40808,7 @@
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
     field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6
+    field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDMAN = 4; // 0x4
     field public static final int UI_TYPE_DIALOG = 3; // 0x3
     field public static final int UI_TYPE_INLINE = 2; // 0x2
     field public static final int UI_TYPE_MENU = 1; // 0x1
@@ -41973,6 +42094,7 @@
 
   public abstract class QuickAccessWalletService extends android.app.Service {
     ctor public QuickAccessWalletService();
+    method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") @Nullable public android.app.PendingIntent getGestureTargetActivityPendingIntent();
     method @Nullable public android.app.PendingIntent getTargetActivityPendingIntent();
     method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onWalletCardSelected(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest);
@@ -46650,6 +46772,8 @@
     method public long getDataUsageBytes();
     method public long getDataUsageTime();
     method @NonNull public int[] getNetworkTypes();
+    method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @Nullable public java.time.ZonedDateTime getPlanEndDate();
+    method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public int getSubscriptionStatus();
     method @Nullable public CharSequence getSummary();
     method @Nullable public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
@@ -46660,6 +46784,11 @@
     field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0
     field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2
     field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff
+    field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_ACTIVE = 1; // 0x1
+    field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_INACTIVE = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4; // 0x4
+    field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_TRIAL = 3; // 0x3
+    field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0; // 0x0
     field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
   }
 
@@ -46671,6 +46800,7 @@
     method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
     method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
     method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@NonNull int[]);
+    method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @NonNull public android.telephony.SubscriptionPlan.Builder setSubscriptionStatus(int);
     method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence);
     method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence);
   }
@@ -49650,6 +49780,14 @@
     method public abstract void updateMeasureState(@NonNull android.text.TextPaint);
   }
 
+  @FlaggedApi("android.view.inputmethod.writing_tools") public final class NoWritingToolsSpan implements android.text.ParcelableSpan {
+    ctor public NoWritingToolsSpan();
+    method public int describeContents();
+    method public int getSpanTypeId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.text.style.NoWritingToolsSpan> CREATOR;
+  }
+
   public interface ParagraphStyle {
   }
 
@@ -51401,6 +51539,7 @@
     method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
     method public default int getBufferTransformHint();
     method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.window.InputTransferToken getInputTransferToken();
+    method @FlaggedApi("com.android.window.flags.jank_api") @NonNull public default android.view.SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.OnJankDataListener);
     method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener);
     method public default void setChildBoundingInsets(@NonNull android.graphics.Rect);
     method public default void setTouchableRegion(@Nullable android.graphics.Region);
@@ -51658,6 +51797,7 @@
     field public static final int DEADLINE = 13; // 0xd
     field public static final int DRAW_DURATION = 4; // 0x4
     field public static final int FIRST_DRAW_FRAME = 9; // 0x9
+    field @FlaggedApi("com.android.window.flags.jank_api") public static final int FRAME_TIMELINE_VSYNC_ID = 14; // 0xe
     field public static final int GPU_DURATION = 12; // 0xc
     field public static final int INPUT_HANDLING_DURATION = 1; // 0x1
     field public static final int INTENDED_VSYNC_TIMESTAMP = 10; // 0xa
@@ -53095,6 +53235,26 @@
     method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl);
   }
 
+  @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.JankData {
+    method public long getActualAppFrameTimeNanos();
+    method public int getJankType();
+    method public long getScheduledAppFrameTimeNanos();
+    method public long getVsyncId();
+    field public static final int JANK_APPLICATION = 2; // 0x2
+    field public static final int JANK_COMPOSER = 1; // 0x1
+    field public static final int JANK_NONE = 0; // 0x0
+    field public static final int JANK_OTHER = 4; // 0x4
+  }
+
+  @FlaggedApi("com.android.window.flags.jank_api") public static interface SurfaceControl.OnJankDataListener {
+    method public void onJankDataAvailable(@NonNull java.util.List<android.view.SurfaceControl.JankData>);
+  }
+
+  @FlaggedApi("com.android.window.flags.jank_api") public static class SurfaceControl.OnJankDataListenerRegistration {
+    method public void flush();
+    method public void removeAfter(long);
+  }
+
   public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
     ctor public SurfaceControl.Transaction();
     method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
@@ -53124,6 +53284,7 @@
     method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long);
     method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
     method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
+    method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.view.SurfaceControl.Transaction setLuts(@NonNull android.view.SurfaceControl, @Nullable android.hardware.DisplayLuts);
     method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
     method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
     method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float);
@@ -54798,6 +54959,8 @@
     method public abstract void setTransformation(android.graphics.Matrix);
     method public abstract void setVisibility(int);
     method public abstract void setWebDomain(@Nullable String);
+    field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE";
+    field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER";
   }
 
   public abstract static class ViewStructure.HtmlInfo {
@@ -56520,6 +56683,11 @@
   public final class AutofillId implements android.os.Parcelable {
     method @NonNull public static android.view.autofill.AutofillId create(@NonNull android.view.View, int);
     method public int describeContents();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getAutofillVirtualId();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getViewId();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isInAutofillSession();
+    method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isVirtual();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.autofill.AutofillId> CREATOR;
   }
@@ -56907,6 +57075,7 @@
     ctor public EditorInfo();
     method public int describeContents();
     method public void dump(android.util.Printer, String);
+    method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") @Nullable public android.view.autofill.AutofillId getAutofillId();
     method @Nullable public CharSequence getInitialSelectedText(int);
     method @Nullable public android.view.inputmethod.SurroundingText getInitialSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
     method @Nullable public CharSequence getInitialTextAfterCursor(@IntRange(from=0) int, int);
@@ -56915,13 +57084,16 @@
     method @NonNull public java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>> getSupportedHandwritingGesturePreviews();
     method @NonNull public java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>> getSupportedHandwritingGestures();
     method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public boolean isStylusHandwritingEnabled();
+    method @FlaggedApi("android.view.inputmethod.writing_tools") public boolean isWritingToolsEnabled();
     method public final void makeCompatible(int);
+    method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") public void setAutofillId(@Nullable android.view.autofill.AutofillId);
     method public void setInitialSurroundingSubText(@NonNull CharSequence, int);
     method public void setInitialSurroundingText(@NonNull CharSequence);
     method public void setInitialToolType(int);
     method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public void setStylusHandwritingEnabled(boolean);
     method public void setSupportedHandwritingGesturePreviews(@NonNull java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>>);
     method public void setSupportedHandwritingGestures(@NonNull java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>>);
+    method @FlaggedApi("android.view.inputmethod.writing_tools") public void setWritingToolsEnabled(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR;
     field public static final int IME_ACTION_DONE = 6; // 0x6
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 4ada53e..ad5bd31 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -1,4 +1,10 @@
 // Baseline format: 1.0
+ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_TYPE:
+    Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE`
+ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER:
+    Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`
+
+
 BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
     Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior
 BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
@@ -1185,6 +1191,10 @@
     New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xlarge
 UnflaggedApi: android.R.dimen#system_corner_radius_xsmall:
     New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xsmall
+UnflaggedApi: android.R.integer#status_bar_notification_info_maxnum:
+    Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.integer.status_bar_notification_info_maxnum
+UnflaggedApi: android.R.string#status_bar_notification_info_overflow:
+    Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.string.status_bar_notification_info_overflow
 UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR:
     New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR
 UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID:
@@ -1477,7 +1487,6 @@
     New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int)
 UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
     New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
-
 UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
     New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
 UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index bc73220..1a949d84 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -251,6 +251,10 @@
 
 package android.net {
 
+  @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava {
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers();
+  }
+
   public class LocalSocket implements java.io.Closeable {
     ctor public LocalSocket(@NonNull java.io.FileDescriptor);
   }
@@ -310,6 +314,25 @@
 
 }
 
+package android.net.vcn {
+
+  @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents();
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions();
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds();
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long);
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnTransportInfo> CREATOR;
+  }
+
+  @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder {
+    ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder();
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build();
+    method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int);
+  }
+
+}
+
 package android.net.wifi {
 
   public final class WifiMigration {
@@ -379,6 +402,13 @@
     field public static final int DEVICE_INITIAL_SDK_INT;
   }
 
+  public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
+    method @FlaggedApi("android.os.enable_has_binders") public int hasBinders();
+    field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_NOT_PRESENT = 0; // 0x0
+    field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_PRESENT = 1; // 0x1
+    field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_UNKNOWN = 2; // 0x2
+  }
+
   public class Handler {
     method @FlaggedApi("android.os.mainline_vcn_platform_api") public final boolean hasMessagesOrCallbacks();
     method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeCallbacksAndEqualMessages(@Nullable Object);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c9a27b4..25434e8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -57,6 +57,7 @@
     field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
     field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE";
+    field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String BIND_DEPENDENCY_INSTALLER = "android.permission.BIND_DEPENDENCY_INSTALLER";
     field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
     field public static final String BIND_DISPLAY_HASHING_SERVICE = "android.permission.BIND_DISPLAY_HASHING_SERVICE";
     field @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public static final String BIND_DOMAIN_SELECTION_SERVICE = "android.permission.BIND_DOMAIN_SELECTION_SERVICE";
@@ -65,6 +66,7 @@
     field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String BIND_EXPLICIT_HEALTH_CHECK_SERVICE = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
     field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE";
     field public static final String BIND_FIELD_CLASSIFICATION_SERVICE = "android.permission.BIND_FIELD_CLASSIFICATION_SERVICE";
+    field @FlaggedApi("android.security.afl_api") public static final String BIND_FORENSIC_EVENT_TRANSPORT_SERVICE = "android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE";
     field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE";
     field public static final String BIND_HOTWORD_DETECTION_SERVICE = "android.permission.BIND_HOTWORD_DETECTION_SERVICE";
     field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
@@ -164,6 +166,7 @@
     field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
     field @Deprecated public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
     field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
+    field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String INSTALL_DEPENDENCY_SHARED_LIBRARIES = "android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES";
     field public static final String INSTALL_DPC_PACKAGES = "android.permission.INSTALL_DPC_PACKAGES";
     field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
     field public static final String INSTALL_EXISTING_PACKAGES = "com.android.permission.INSTALL_EXISTING_PACKAGES";
@@ -209,6 +212,7 @@
     field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String MANAGE_ENHANCED_CONFIRMATION_STATES = "android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES";
     field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
     field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
+    field @FlaggedApi("android.security.afl_api") public static final String MANAGE_FORENSIC_STATE = "android.permission.MANAGE_FORENSIC_STATE";
     field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY";
     field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE";
     field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE";
@@ -304,6 +308,7 @@
     field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
     field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
     field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
+    field @FlaggedApi("android.security.afl_api") public static final String READ_FORENSIC_STATE = "android.permission.READ_FORENSIC_STATE";
     field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA";
     field @FlaggedApi("android.content.pm.get_resolved_apk_path") public static final String READ_INSTALLED_SESSION_PATHS = "android.permission.READ_INSTALLED_SESSION_PATHS";
     field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
@@ -528,6 +533,7 @@
     field public static final int config_systemCallStreaming = 17039431; // 0x1040047
     field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039
     field public static final int config_systemContacts = 17039403; // 0x104002b
+    field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final int config_systemDependencyInstaller;
     field public static final int config_systemFinancedDeviceController = 17039430; // 0x1040046
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035
@@ -1336,8 +1342,10 @@
   public class DevicePolicyManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void clearAuditLogEventCallback();
-    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+    method @Deprecated @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+    method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
     method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+    method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeCreateManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams, @NonNull android.os.UserHandle) throws android.app.admin.ProvisioningException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public java.util.Set<java.lang.Integer> getApplicationExemptions(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
@@ -1932,6 +1940,7 @@
     method public android.os.IBinder getBinder();
     method public long getCurrentRestoreSet();
     method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
+    method @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") @NonNull public java.util.List<java.lang.String> getPackagesThatShouldNotUseRestrictedMode(@NonNull java.util.List<java.lang.String>, int);
     method public int getRestoreData(android.os.ParcelFileDescriptor);
     method public int getTransportFlags();
     method public int initializeDevice();
@@ -4585,6 +4594,24 @@
 
 }
 
+package android.content.pm.dependencyinstaller {
+
+  @FlaggedApi("android.content.pm.sdk_dependency_installer") public final class DependencyInstallerCallback implements android.os.Parcelable {
+    method public int describeContents();
+    method public void onAllDependenciesResolved(@NonNull int[]);
+    method public void onFailureToResolveAllDependencies();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.dependencyinstaller.DependencyInstallerCallback> CREATOR;
+  }
+
+  @FlaggedApi("android.content.pm.sdk_dependency_installer") public abstract class DependencyInstallerService extends android.app.Service {
+    ctor public DependencyInstallerService();
+    method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onDependenciesRequired(@NonNull java.util.List<android.content.pm.SharedLibraryInfo>, @NonNull android.content.pm.dependencyinstaller.DependencyInstallerCallback);
+  }
+
+}
+
 package android.content.pm.dex {
 
   public class ArtManager {
@@ -5045,15 +5072,27 @@
 
 package android.hardware.camera2 {
 
+  public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CameraCharacteristics.Key<?>> {
+    field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION;
+  }
+
   public abstract class CameraDevice implements java.lang.AutoCloseable {
     method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1
     field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0
+    field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_OPERATION_MODE_SHARED = 2; // 0x2
     field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
   }
 
+  public abstract static class CameraDevice.StateCallback {
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onClientSharedAccessPriorityChanged(@NonNull android.hardware.camera2.CameraDevice, boolean);
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onOpenedInSharedMode(@NonNull android.hardware.camera2.CameraDevice, boolean);
+  }
+
   public final class CameraManager {
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public boolean isCameraDeviceSharingSupported(@NonNull String) throws android.hardware.camera2.CameraAccessException;
     method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openSharedCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
   }
 
   public abstract static class CameraManager.AvailabilityCallback {
@@ -5061,6 +5100,12 @@
     method @RequiresPermission(android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER) public void onCameraOpened(@NonNull String, @NonNull String);
   }
 
+  @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract class CameraSharedCaptureSession extends android.hardware.camera2.CameraCaptureSession {
+    ctor public CameraSharedCaptureSession();
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract int startStreaming(@NonNull java.util.List<android.view.Surface>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+    method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract void stopStreaming() throws android.hardware.camera2.CameraAccessException;
+  }
+
 }
 
 package android.hardware.camera2.extension {
@@ -5169,6 +5214,107 @@
     field public static final int ROTATION_90 = 1; // 0x1
   }
 
+  public final class SessionConfiguration implements android.os.Parcelable {
+    field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_SHARED = 2; // 0x2
+  }
+
+  @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public final class SharedSessionConfiguration {
+    method @Nullable public android.graphics.ColorSpace getColorSpace();
+    method @NonNull public java.util.List<android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration> getOutputStreamsInformation();
+  }
+
+  public static final class SharedSessionConfiguration.SharedOutputConfiguration {
+    method public int getDataspace();
+    method public int getFormat();
+    method public int getMirrorMode();
+    method @Nullable public String getPhysicalCameraId();
+    method @NonNull public android.util.Size getSize();
+    method public long getStreamUseCase();
+    method public int getSurfaceType();
+    method public int getTimestampBase();
+    method public long getUsage();
+    method public boolean isReadoutTimestampEnabled();
+  }
+
+}
+
+package android.hardware.contexthub {
+
+  @FlaggedApi("android.chre.flags.offload_api") public class HubDiscoveryInfo {
+    method @NonNull public android.hardware.contexthub.HubEndpointInfo getHubEndpointInfo();
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public class HubEndpoint {
+    method @Nullable public android.hardware.contexthub.IHubEndpointLifecycleCallback getLifecycleCallback();
+    method @Nullable public android.hardware.contexthub.IHubEndpointMessageCallback getMessageCallback();
+    method @Nullable public String getTag();
+  }
+
+  public static final class HubEndpoint.Builder {
+    ctor public HubEndpoint.Builder(@NonNull android.content.Context);
+    method @NonNull public android.hardware.contexthub.HubEndpoint build();
+    method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback);
+    method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback);
+    method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull android.hardware.contexthub.IHubEndpointMessageCallback);
+    method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointMessageCallback);
+    method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setTag(@NonNull String);
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public final class HubEndpointInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier getIdentifier();
+    method @NonNull public String getName();
+    method @Nullable public String getTag();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubEndpointInfo> CREATOR;
+  }
+
+  public static class HubEndpointInfo.HubEndpointIdentifier {
+    method public long getEndpoint();
+    method public long getHub();
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable {
+    method public void close();
+    method @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> sendMessage(@NonNull android.hardware.contexthub.HubMessage);
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSessionResult {
+    method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult accept();
+    method @Nullable public String getReason();
+    method public boolean isAccepted();
+    method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult reject(@NonNull String);
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public final class HubMessage implements android.os.Parcelable {
+    method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[]);
+    method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[], @NonNull android.hardware.contexthub.HubMessage.DeliveryParams);
+    method public int describeContents();
+    method @NonNull public byte[] getMessageBody();
+    method public int getMessageType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubMessage> CREATOR;
+  }
+
+  public static class HubMessage.DeliveryParams {
+    method public boolean isResponseRequired();
+    method @NonNull public static android.hardware.contexthub.HubMessage.DeliveryParams makeBasic();
+    method @NonNull public android.hardware.contexthub.HubMessage.DeliveryParams setResponseRequired(boolean);
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback {
+    method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int);
+    method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo);
+    method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession);
+    field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4
+    field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3
+    field public static final int REASON_UNSPECIFIED = 0; // 0x0
+  }
+
+  @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback {
+    method public void onMessageReceived(@NonNull android.hardware.contexthub.HubEndpointSession, @NonNull android.hardware.contexthub.HubMessage);
+  }
+
 }
 
 package android.hardware.devicestate {
@@ -5301,6 +5447,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
     method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve();
     method public android.graphics.Point getStableDisplaySize();
+    method @FlaggedApi("com.android.server.display.feature.flags.is_always_on_available_api") public boolean isAlwaysOnDisplayCurrentlyAvailable();
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
@@ -6162,6 +6309,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(long);
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] getContextHubHandles();
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
@@ -6169,13 +6317,16 @@
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
     method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
+    method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint);
     field public static final int AUTHORIZATION_DENIED = 0; // 0x0
     field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1
     field public static final int AUTHORIZATION_GRANTED = 2; // 0x2
@@ -6231,6 +6382,8 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
     field public static final int TYPE_DISABLE_NANOAPP = 3; // 0x3
     field public static final int TYPE_ENABLE_NANOAPP = 2; // 0x2
+    field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_DEFAULT = 6; // 0x6
+    field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7; // 0x7
     field public static final int TYPE_LOAD_NANOAPP = 0; // 0x0
     field public static final int TYPE_QUERY_NANOAPPS = 4; // 0x4
     field public static final int TYPE_RELIABLE_MESSAGE = 5; // 0x5
@@ -7464,6 +7617,7 @@
   }
 
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
+    method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceInfo> getAudioDeviceInfos();
     method public int getChannelMask();
     method public int getClientPid();
     method public int getClientUid();
@@ -7618,7 +7772,7 @@
 
   public final class MediaCas implements java.lang.AutoCloseable {
     method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean);
-    method @FlaggedApi("com.android.media.flags.update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int);
+    method @FlaggedApi("android.media.tv.flags.mediacas_update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int);
   }
 
   public final class MediaCodec {
@@ -12553,8 +12707,42 @@
   }
 
   @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
+    method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String);
     method @NonNull @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
     method @RequiresPermission(android.Manifest.permission.SET_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
+    field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
+    field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
+    field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
+    field public static final String FEATURE_ID_DISALLOW_CELLULAR_2G = "android.security.advancedprotection.feature_disallow_2g";
+    field public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = "android.security.advancedprotection.feature_disallow_install_unknown_sources";
+    field public static final String FEATURE_ID_DISALLOW_USB = "android.security.advancedprotection.feature_disallow_usb";
+    field public static final String FEATURE_ID_DISALLOW_WEP = "android.security.advancedprotection.feature_disallow_wep";
+    field public static final String FEATURE_ID_ENABLE_MTE = "android.security.advancedprotection.feature_enable_mte";
+    field public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = "android.security.advancedprotection.type_blocked_interaction";
+    field public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING = "android.security.advancedprotection.type_disabled_setting";
+  }
+
+}
+
+package android.security.forensic {
+
+  @FlaggedApi("android.security.afl_api") public class ForensicManager {
+    method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void enable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void removeStateCallback(@NonNull java.util.function.Consumer<java.lang.Integer>);
+    field public static final int ERROR_DATA_SOURCE_UNAVAILABLE = 4; // 0x4
+    field public static final int ERROR_PERMISSION_DENIED = 1; // 0x1
+    field public static final int ERROR_TRANSPORT_UNAVAILABLE = 3; // 0x3
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_DISABLED = 1; // 0x1
+    field public static final int STATE_ENABLED = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public static interface ForensicManager.CommandCallback {
+    method public void onFailure(int);
+    method public void onSuccess();
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c8ecfa9..8fd2cd5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2065,6 +2065,29 @@
     method public boolean isAidlHal();
   }
 
+  public final class MediaCodec {
+    method @FlaggedApi("android.media.codec.codec_availability") @NonNull public static java.util.List<android.media.MediaCodec.GlobalResourceInfo> getGloballyAvailableResources();
+    method @FlaggedApi("android.media.codec.codec_availability") @NonNull public java.util.List<android.media.MediaCodec.InstanceResourceInfo> getRequiredResources();
+  }
+
+  public abstract static class MediaCodec.Callback {
+    method @FlaggedApi("android.media.codec.codec_availability") public void onRequiredResourcesChanged(@NonNull android.media.MediaCodec);
+  }
+
+  @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.GlobalResourceInfo {
+    ctor public MediaCodec.GlobalResourceInfo();
+    method public long getAvailable();
+    method public long getCapacity();
+    method @NonNull public String getName();
+  }
+
+  @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.InstanceResourceInfo {
+    ctor public MediaCodec.InstanceResourceInfo();
+    method @NonNull public String getName();
+    method public long getPerFrameCount();
+    method public long getStaticCount();
+  }
+
   public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
     ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
     ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
@@ -2295,7 +2318,7 @@
 
   public class SharedConnectivityManager {
     method @Nullable public static android.net.wifi.sharedconnectivity.app.SharedConnectivityManager create(@NonNull android.content.Context, @NonNull String, @NonNull String);
-    method @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api") @NonNull public android.content.BroadcastReceiver getBroadcastReceiver();
+    method @NonNull public android.content.BroadcastReceiver getBroadcastReceiver();
     method @Nullable public android.content.ServiceConnection getServiceConnection();
     method public void setService(@Nullable android.os.IInterface);
   }
@@ -3217,6 +3240,7 @@
     method @Nullable public android.content.Intent createWalletIntent();
     method @Nullable public android.content.Intent createWalletSettingsIntent();
     method public void disconnect();
+    method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void getGestureTargetActivityPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.GesturePendingIntentCallback);
     method public void getWalletCards(@NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
     method public void getWalletCards(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback);
     method public void getWalletPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.WalletPendingIntentCallback);
@@ -3228,6 +3252,10 @@
     method public void selectWalletCard(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest);
   }
 
+  @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public static interface QuickAccessWalletClient.GesturePendingIntentCallback {
+    method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void onGesturePendingIntentRetrieved(@Nullable android.app.PendingIntent);
+  }
+
   public static interface QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
     method public void onWalletCardRetrievalError(@NonNull android.service.quickaccesswallet.GetWalletCardsError);
     method public void onWalletCardsRetrieved(@NonNull android.service.quickaccesswallet.GetWalletCardsResponse);
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 08bb082..c2fac70 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1,4 +1,10 @@
 // Baseline format: 1.0
+ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_TYPE:
+    Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE`
+ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER:
+    Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`
+
+
 BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer):
     Methods must not throw unchecked exceptions
 
diff --git a/core/java/Android.bp b/core/java/Android.bp
index cf5ebbaa3..bc38294 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -232,6 +232,8 @@
         "android.hardware.power-aidl",
     ],
     srcs: [
+        "android/os/CpuHeadroomParamsInternal.aidl",
+        "android/os/GpuHeadroomParamsInternal.aidl",
         "android/os/IHintManager.aidl",
         "android/os/IHintSession.aidl",
     ],
diff --git a/core/java/android/adaptiveauth/OWNERS b/core/java/android/adaptiveauth/OWNERS
index bc8efa9..4310d1a 100644
--- a/core/java/android/adaptiveauth/OWNERS
+++ b/core/java/android/adaptiveauth/OWNERS
@@ -1 +1 @@
-include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1b707f7..ab75069 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -5300,7 +5300,6 @@
         if (!exported) {
             /*
             RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
             Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
                     here);
             */
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 60b8f80..cb7b115 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1961,12 +1961,8 @@
 
         @Override
         public void dumpCacheInfo(ParcelFileDescriptor pfd, String[] args) {
-            try {
-                PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
-                BroadcastStickyCache.dump(pfd);
-            } finally {
-                IoUtils.closeQuietly(pfd);
-            }
+            PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
+            IoUtils.closeQuietly(pfd);
         }
 
         private File getDatabasesDir(Context context) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8b37dbd..ce0ec60 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1624,9 +1624,19 @@
     /** @hide Access to read oxygen saturation. */
     public static final int OP_READ_OXYGEN_SATURATION = AppOpEnums.APP_OP_READ_OXYGEN_SATURATION;
 
+    /** @hide Access to write system preferences. */
+    public static final int OP_WRITE_SYSTEM_PREFERENCES =
+            AppOpEnums.APP_OP_WRITE_SYSTEM_PREFERENCES;
+
+    /** @hide Access to audio playback and control APIs. */
+    public static final int OP_CONTROL_AUDIO = AppOpEnums.APP_OP_CONTROL_AUDIO;
+
+    /** @hide Similar to {@link OP_CONTROL_AUDIO}, but doesn't require capabilities. */
+    public static final int OP_CONTROL_AUDIO_PARTIAL = AppOpEnums.APP_OP_CONTROL_AUDIO_PARTIAL;
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int _NUM_OP = 153;
+    public static final int _NUM_OP = 156;
 
     /**
      * All app ops represented as strings.
@@ -1783,6 +1793,9 @@
             OPSTR_READ_SKIN_TEMPERATURE,
             OPSTR_RANGING,
             OPSTR_READ_OXYGEN_SATURATION,
+            OPSTR_WRITE_SYSTEM_PREFERENCES,
+            OPSTR_CONTROL_AUDIO,
+            OPSTR_CONTROL_AUDIO_PARTIAL,
     })
     public @interface AppOpString {}
 
@@ -2540,6 +2553,15 @@
     @FlaggedApi(Flags.FLAG_RANGING_PERMISSION_ENABLED)
     public static final String OPSTR_RANGING = "android:ranging";
 
+    /** @hide Access to system preferences write services */
+    public static final String OPSTR_WRITE_SYSTEM_PREFERENCES = "android:write_system_preferences";
+
+    /** @hide Access to audio playback and control APIs */
+    public static final String OPSTR_CONTROL_AUDIO = "android:control_audio";
+
+    /** @hide Access to a audio playback and control APIs without capability requirements */
+    public static final String OPSTR_CONTROL_AUDIO_PARTIAL = "android:control_audio_partial";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2656,6 +2678,7 @@
             OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
             OP_MEDIA_ROUTING_CONTROL,
             OP_READ_SYSTEM_GRAMMATICAL_GENDER,
+            OP_WRITE_SYSTEM_PREFERENCES,
     };
 
     @SuppressWarnings("FlaggedApi")
@@ -3144,6 +3167,14 @@
                 Flags.replaceBodySensorPermissionEnabled()
                     ? HealthPermissions.READ_OXYGEN_SATURATION : null)
             .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+        new AppOpInfo.Builder(OP_WRITE_SYSTEM_PREFERENCES, OPSTR_WRITE_SYSTEM_PREFERENCES,
+            "WRITE_SYSTEM_PREFERENCES").setPermission(
+                     com.android.settingslib.flags.Flags.writeSystemPreferencePermissionEnabled()
+                     ? Manifest.permission.WRITE_SYSTEM_PREFERENCES : null).build(),
+        new AppOpInfo.Builder(OP_CONTROL_AUDIO, OPSTR_CONTROL_AUDIO,
+                "CONTROL_AUDIO").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(),
+        new AppOpInfo.Builder(OP_CONTROL_AUDIO_PARTIAL, OPSTR_CONTROL_AUDIO_PARTIAL,
+                "CONTROL_AUDIO_PARTIAL").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(),
     };
 
     // The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index fb5a12b..7e0a9b6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
 import static android.app.PropertyInvalidatedCache.createSystemCacheKey;
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
 import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
@@ -783,43 +784,24 @@
     }
 
     /**
+     * The API and cache name for hasSystemFeature.
+     */
+    private static final String HAS_SYSTEM_FEATURE_API = "has_system_feature";
+
+    /**
      * Identifies a single hasSystemFeature query.
      */
-    @Immutable
-    private static final class HasSystemFeatureQuery {
-        public final String name;
-        public final int version;
-        public HasSystemFeatureQuery(String n, int v) {
-            name = n;
-            version = v;
-        }
-        @Override
-        public String toString() {
-            return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)",
-                    name, version);
-        }
-        @Override
-        public boolean equals(@Nullable Object o) {
-            if (o instanceof HasSystemFeatureQuery) {
-                HasSystemFeatureQuery r = (HasSystemFeatureQuery) o;
-                return Objects.equals(name, r.name) &&  version == r.version;
-            } else {
-                return false;
-            }
-        }
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(name) * 13 + version;
-        }
-    }
+    private record HasSystemFeatureQuery(String name, int version) {}
 
     // Make this cache relatively large.  There are many system features and
     // none are ever invalidated.  MPTS tests suggests that the cache should
     // hold at least 150 entries.
     private final static PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>
-            mHasSystemFeatureCache =
-            new PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>(
-                256, createSystemCacheKey("has_system_feature")) {
+            mHasSystemFeatureCache = new PropertyInvalidatedCache<>(
+                new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+                .api(HAS_SYSTEM_FEATURE_API).maxEntries(256).isolateUids(false),
+                HAS_SYSTEM_FEATURE_API, null) {
+
                 @Override
                 public Boolean recompute(HasSystemFeatureQuery query) {
                     try {
@@ -1835,7 +1817,6 @@
 
                 if (false) {
                     RuntimeException e = new RuntimeException("here");
-                    e.fillInStackTrace();
                     Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
                                     + " from package " + packageName
                                     + ": app scale=" + r.getCompatibilityInfo().applicationScale
diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java
deleted file mode 100644
index ea81731..0000000
--- a/core/java/android/app/BroadcastStickyCache.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbManager;
-import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.net.TetheringManager;
-import android.net.nsd.NsdManager;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemProperties;
-import android.os.UpdateLock;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-import android.util.IndentingPrintWriter;
-import android.view.WindowManagerPolicyConstants;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/** @hide */
-public class BroadcastStickyCache {
-
-    private static final String[] CACHED_BROADCAST_ACTIONS = {
-            AudioManager.ACTION_HDMI_AUDIO_PLUG,
-            AudioManager.ACTION_HEADSET_PLUG,
-            AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED,
-            AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED,
-            AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION,
-            AudioManager.RINGER_MODE_CHANGED_ACTION,
-            ConnectivityManager.CONNECTIVITY_ACTION,
-            Intent.ACTION_BATTERY_CHANGED,
-            Intent.ACTION_DEVICE_STORAGE_FULL,
-            Intent.ACTION_DEVICE_STORAGE_LOW,
-            Intent.ACTION_SIM_STATE_CHANGED,
-            NsdManager.ACTION_NSD_STATE_CHANGED,
-            TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED,
-            TetheringManager.ACTION_TETHER_STATE_CHANGED,
-            UpdateLock.UPDATE_LOCK_CHANGED,
-            UsbManager.ACTION_USB_STATE,
-            WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED,
-            WifiManager.NETWORK_STATE_CHANGED_ACTION,
-            WifiManager.SUPPLICANT_STATE_CHANGED_ACTION,
-            WifiManager.WIFI_STATE_CHANGED_ACTION,
-            WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
-            WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED,
-            "android.net.conn.INET_CONDITION_ACTION" // ConnectivityManager.INET_CONDITION_ACTION
-    };
-
-    @GuardedBy("sCachedStickyBroadcasts")
-    private static final ArrayList<CachedStickyBroadcast> sCachedStickyBroadcasts =
-            new ArrayList<>();
-
-    @GuardedBy("sCachedPropertyHandles")
-    private static final ArrayMap<String, SystemProperties.Handle> sCachedPropertyHandles =
-            new ArrayMap<>();
-
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public static boolean useCache(@Nullable IntentFilter filter) {
-        if (!shouldCache(filter)) {
-            return false;
-        }
-        synchronized (sCachedStickyBroadcasts) {
-            final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
-            if (cachedStickyBroadcast == null) {
-                return false;
-            }
-            final long version = cachedStickyBroadcast.propertyHandle.getLong(-1 /* def */);
-            return version > 0 && cachedStickyBroadcast.version == version;
-        }
-    }
-
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    public static void add(@Nullable IntentFilter filter, @Nullable Intent intent) {
-        if (!shouldCache(filter)) {
-            return;
-        }
-        synchronized (sCachedStickyBroadcasts) {
-            CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
-            if (cachedStickyBroadcast == null) {
-                final String key = getKey(filter.getAction(0));
-                final SystemProperties.Handle handle = SystemProperties.find(key);
-                final long version = handle == null ? -1 : handle.getLong(-1 /* def */);
-                if (version == -1) {
-                    return;
-                }
-                cachedStickyBroadcast = new CachedStickyBroadcast(filter, handle);
-                sCachedStickyBroadcasts.add(cachedStickyBroadcast);
-                cachedStickyBroadcast.intent = intent;
-                cachedStickyBroadcast.version = version;
-            } else {
-                cachedStickyBroadcast.intent = intent;
-                cachedStickyBroadcast.version = cachedStickyBroadcast.propertyHandle
-                        .getLong(-1 /* def */);
-            }
-        }
-    }
-
-    private static boolean shouldCache(@Nullable IntentFilter filter) {
-        if (!Flags.useStickyBcastCache()) {
-            return false;
-        }
-        if (filter == null || filter.safeCountActions() != 1) {
-            return false;
-        }
-        if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, filter.getAction(0))) {
-            return false;
-        }
-        return true;
-    }
-
-    @VisibleForTesting
-    @NonNull
-    public static String getKey(@NonNull String action) {
-        return "cache_key.system_server.sticky_bcast." + action;
-    }
-
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    @Nullable
-    public static Intent getIntentUnchecked(@NonNull IntentFilter filter) {
-        synchronized (sCachedStickyBroadcasts) {
-            final CachedStickyBroadcast cachedStickyBroadcast = getValueUncheckedLocked(filter);
-            return cachedStickyBroadcast.intent;
-        }
-    }
-
-    @GuardedBy("sCachedStickyBroadcasts")
-    @Nullable
-    private static CachedStickyBroadcast getValueUncheckedLocked(@NonNull IntentFilter filter) {
-        for (int i = sCachedStickyBroadcasts.size() - 1; i >= 0; --i) {
-            final CachedStickyBroadcast cachedStickyBroadcast = sCachedStickyBroadcasts.get(i);
-            if (IntentFilter.filterEquals(filter, cachedStickyBroadcast.filter)) {
-                return cachedStickyBroadcast;
-            }
-        }
-        return null;
-    }
-
-    public static void incrementVersion(@NonNull String action) {
-        if (!shouldIncrementVersion(action)) {
-            return;
-        }
-        final String key = getKey(action);
-        synchronized (sCachedPropertyHandles) {
-            SystemProperties.Handle handle = sCachedPropertyHandles.get(key);
-            final long version;
-            if (handle == null) {
-                handle = SystemProperties.find(key);
-                if (handle != null) {
-                    sCachedPropertyHandles.put(key, handle);
-                }
-            }
-            version = handle == null ? 0 : handle.getLong(0 /* def */);
-            SystemProperties.set(key, String.valueOf(version + 1));
-            if (handle == null) {
-                sCachedPropertyHandles.put(key, SystemProperties.find(key));
-            }
-        }
-    }
-
-    public static void incrementVersionIfExists(@NonNull String action) {
-        if (!shouldIncrementVersion(action)) {
-            return;
-        }
-        final String key = getKey(action);
-        synchronized (sCachedPropertyHandles) {
-            final SystemProperties.Handle handle = sCachedPropertyHandles.get(key);
-            if (handle == null) {
-                return;
-            }
-            final long version = handle.getLong(0 /* def */);
-            SystemProperties.set(key, String.valueOf(version + 1));
-        }
-    }
-
-    private static boolean shouldIncrementVersion(@NonNull String action) {
-        if (!Flags.useStickyBcastCache()) {
-            return false;
-        }
-        if (!ArrayUtils.contains(CACHED_BROADCAST_ACTIONS, action)) {
-            return false;
-        }
-        return true;
-    }
-
-    @VisibleForTesting
-    public static void clearForTest() {
-        synchronized (sCachedStickyBroadcasts) {
-            sCachedStickyBroadcasts.clear();
-        }
-        synchronized (sCachedPropertyHandles) {
-            sCachedPropertyHandles.clear();
-        }
-    }
-
-    public static void dump(@NonNull ParcelFileDescriptor pfd) {
-        if (!Flags.useStickyBcastCache()) {
-            return;
-        }
-        final PrintWriter pw = new FastPrintWriter(new FileOutputStream(pfd.getFileDescriptor()));
-        synchronized (sCachedStickyBroadcasts) {
-            dumpLocked(pw);
-        }
-        pw.flush();
-    }
-
-    @GuardedBy("sCachedStickyBroadcasts")
-    private static void dumpLocked(@NonNull PrintWriter pw) {
-        final IndentingPrintWriter ipw = new IndentingPrintWriter(
-                pw, "  " /* singleIndent */, "  " /* prefix */);
-        ipw.println("Cached sticky broadcasts:");
-        ipw.increaseIndent();
-        final int count = sCachedStickyBroadcasts.size();
-        if (count == 0) {
-            ipw.println("<empty>");
-        } else {
-            for (int i = 0; i < count; ++i) {
-                final CachedStickyBroadcast cachedStickyBroadcast = sCachedStickyBroadcasts.get(i);
-                ipw.print("Entry #"); ipw.print(i); ipw.println(":");
-                ipw.increaseIndent();
-                ipw.print("filter="); ipw.println(cachedStickyBroadcast.filter.toLongString());
-                ipw.print("intent="); ipw.println(cachedStickyBroadcast.intent);
-                ipw.print("version="); ipw.println(cachedStickyBroadcast.version);
-                ipw.print("handle="); ipw.println(cachedStickyBroadcast.propertyHandle);
-                ipw.decreaseIndent();
-            }
-        }
-        ipw.decreaseIndent();
-    }
-
-    private static final class CachedStickyBroadcast {
-        @NonNull public final IntentFilter filter;
-        @Nullable public Intent intent;
-        @IntRange(from = 0) public long version;
-        @NonNull public final SystemProperties.Handle propertyHandle;
-
-        CachedStickyBroadcast(@NonNull IntentFilter filter,
-                @NonNull SystemProperties.Handle propertyHandle) {
-            this.filter = filter;
-            this.propertyHandle = propertyHandle;
-        }
-    }
-}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3ae60d71..cd56957 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1922,19 +1922,10 @@
             }
         }
         try {
-            final Intent intent;
-            if (receiver == null && BroadcastStickyCache.useCache(filter)) {
-                intent = BroadcastStickyCache.getIntentUnchecked(filter);
-            } else {
-                intent = ActivityManager.getService().registerReceiverWithFeature(
-                        mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
-                        AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission,
-                        userId,
-                        flags);
-                if (receiver == null) {
-                    BroadcastStickyCache.add(filter, intent);
-                }
-            }
+            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
+                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
+                    AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
+                    flags);
             if (intent != null) {
                 intent.setExtrasClassLoader(getClassLoader());
                 // TODO: determine at registration time if caller is
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 9615015..7a329cd 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -112,8 +112,8 @@
     oneway void requestMultiwindowFullscreen(in IBinder token, in int request,
             in IRemoteCallback callback);
 
-    oneway void startLockTaskModeByToken(in IBinder token);
-    oneway void stopLockTaskModeByToken(in IBinder token);
+    void startLockTaskModeByToken(in IBinder token);
+    void stopLockTaskModeByToken(in IBinder token);
     oneway void showLockTaskEscapeMessage(in IBinder token);
     void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
 
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 34a3ad1..a8412fa 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -358,7 +358,7 @@
     @UnsupportedAppUsage
     void resumeAppSwitches();
     boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId,
-            int backupDestination);
+            int backupDestination, boolean useRestrictedMode);
     void backupAgentCreated(in String packageName, in IBinder agent, int userId);
     void unbindBackupAgent(in ApplicationInfo appInfo);
     int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0654ac2..9bb16ae 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -124,7 +124,7 @@
     boolean onlyHasDefaultChannel(String pkg, int uid);
     boolean areChannelsBypassingDnd();
     ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid);
-    List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels);
+    ParceledListSlice getPackagesBypassingDnd(int userId);
     boolean isPackagePaused(String pkg);
     void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
     boolean isPermissionFixed(String pkg, int userId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b8233bc..3d85ea6 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1660,7 +1660,6 @@
                         }
                         RuntimeException ex = new IllegalArgumentException(
                                 "Originally unregistered here:");
-                        ex.fillInStackTrace();
                         rd.setUnregisterLocation(ex);
                         holder.put(r, rd);
                     }
@@ -1860,7 +1859,6 @@
             mInstrumentation = instrumentation;
             mRegistered = registered;
             mLocation = new IntentReceiverLeaked(null);
-            mLocation.fillInStackTrace();
         }
 
         void validate(Context context, Handler activityThread) {
@@ -2000,7 +1998,6 @@
                         }
                         RuntimeException ex = new IllegalArgumentException(
                                 "Originally unbound here:");
-                        ex.fillInStackTrace();
                         sd.setUnbindLocation(ex);
                         holder.put(c, sd);
                     }
@@ -2076,7 +2073,6 @@
             mActivityThread = activityThread;
             mActivityExecutor = null;
             mLocation = new ServiceConnectionLeaked(null);
-            mLocation.fillInStackTrace();
             mFlags = flags;
         }
 
@@ -2088,7 +2084,6 @@
             mActivityThread = null;
             mActivityExecutor = activityExecutor;
             mLocation = new ServiceConnectionLeaked(null);
-            mLocation.fillInStackTrace();
             mFlags = flags;
         }
 
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index e2de716..a70d493 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -83,7 +83,7 @@
          * transactions while in this call, since it can happen after an
          * activity's state is saved.  See {@link FragmentManager#beginTransaction()
          * FragmentManager.openTransaction()} for further discussion on this.
-         * 
+         *
          * <p>This function is guaranteed to be called prior to the release of
          * the last data that was supplied for this Loader.  At this point
          * you should remove all use of the old data (since it will be released
@@ -127,7 +127,7 @@
          */
         public void onLoaderReset(Loader<D> loader);
     }
-    
+
     /**
      * Ensures a loader is initialized and active.  If the loader doesn't
      * already exist, one is created and (if the activity/fragment is currently
@@ -228,7 +228,7 @@
     boolean mStarted;
     boolean mRetaining;
     boolean mRetainingStarted;
-    
+
     boolean mCreatingLoader;
     private FragmentHostCallback mHost;
 
@@ -249,13 +249,13 @@
         boolean mListenerRegistered;
 
         LoaderInfo mPendingLoader;
-        
+
         public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
             mId = id;
             mArgs = args;
             mCallbacks = callbacks;
         }
-        
+
         void start() {
             if (mRetaining && mRetainingStarted) {
                 // Our owner is started, but we were being retained from a
@@ -271,7 +271,7 @@
             }
 
             mStarted = true;
-            
+
             if (DEBUG) Log.v(TAG, "  Starting: " + this);
             if (mLoader == null && mCallbacks != null) {
                mLoader = mCallbacks.onCreateLoader(mId, mArgs);
@@ -291,7 +291,7 @@
                 mLoader.startLoading();
             }
         }
-        
+
         void retain() {
             if (DEBUG) Log.v(TAG, "  Retaining: " + this);
             mRetaining = true;
@@ -299,7 +299,7 @@
             mStarted = false;
             mCallbacks = null;
         }
-        
+
         void finishRetain() {
             if (mRetaining) {
                 if (DEBUG) Log.v(TAG, "  Finished Retaining: " + this);
@@ -324,7 +324,7 @@
                 callOnLoadFinished(mLoader, mData);
             }
         }
-        
+
         void reportStart() {
             if (mStarted) {
                 if (mReportNextStart) {
@@ -430,7 +430,7 @@
         @Override
         public void onLoadComplete(Loader<Object> loader, Object data) {
             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
-            
+
             if (mDestroyed) {
                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
                 return;
@@ -442,7 +442,7 @@
                 if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
                 return;
             }
-            
+
             LoaderInfo pending = mPendingLoader;
             if (pending != null) {
                 // There is a new request pending and we were just
@@ -455,7 +455,7 @@
                 installLoader(pending);
                 return;
             }
-            
+
             // Notify of the new data so the app can switch out the old data before
             // we try to destroy it.
             if (mData != data || !mHaveData) {
@@ -503,7 +503,7 @@
                 mDeliveredData = true;
             }
         }
-        
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(64);
@@ -543,13 +543,13 @@
             }
         }
     }
-    
+
     LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
         mWho = who;
         mHost = host;
         mStarted = started;
     }
-    
+
     void updateHostController(FragmentHostCallback host) {
         mHost = host;
     }
@@ -557,7 +557,7 @@
     public FragmentHostCallback getFragmentHostCallback() {
         return mHost;
     }
-    
+
     private LoaderInfo createLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
         LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
@@ -565,7 +565,7 @@
         info.mLoader = (Loader<Object>)loader;
         return info;
     }
-    
+
     private LoaderInfo createAndInstallLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
         try {
@@ -577,7 +577,7 @@
             mCreatingLoader = false;
         }
     }
-    
+
     void installLoader(LoaderInfo info) {
         mLoaders.put(info.mId, info);
         if (mStarted) {
@@ -587,23 +587,23 @@
             info.start();
         }
     }
-    
+
     /**
      * Call to initialize a particular ID with a Loader.  If this ID already
      * has a Loader associated with it, it is left unchanged and any previous
      * callbacks replaced with the newly provided ones.  If there is not currently
      * a Loader for the ID, a new one is created and started.
-     * 
+     *
      * <p>This function should generally be used when a component is initializing,
      * to ensure that a Loader it relies on is created.  This allows it to re-use
      * an existing Loader's data if there already is one, so that for example
      * when an {@link Activity} is re-created after a configuration change it
      * does not need to re-create its loaders.
-     * 
+     *
      * <p>Note that in the case where an existing Loader is re-used, the
      * <var>args</var> given here <em>will be ignored</em> because you will
      * continue using the previous Loader.
-     * 
+     *
      * @param id A unique (to this LoaderManager instance) identifier under
      * which to manage the new Loader.
      * @param args Optional arguments that will be propagated to
@@ -617,9 +617,9 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo info = mLoaders.get(id);
-        
+
         if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
 
         if (info == null) {
@@ -630,30 +630,30 @@
             if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
             info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
         }
-        
+
         if (info.mHaveData && mStarted) {
             // If the loader has already generated its data, report it now.
             info.callOnLoadFinished(info.mLoader, info.mData);
         }
-        
+
         return (Loader<D>)info.mLoader;
     }
-    
+
     /**
      * Call to re-create the Loader associated with a particular ID.  If there
      * is currently a Loader associated with this ID, it will be
      * canceled/stopped/destroyed as appropriate.  A new Loader with the given
      * arguments will be created and its data delivered to you once available.
-     * 
+     *
      * <p>This function does some throttling of Loaders.  If too many Loaders
      * have been created for the given ID but not yet generated their data,
      * new calls to this function will create and return a new Loader but not
      * actually start it until some previous loaders have completed.
-     * 
+     *
      * <p>After calling this function, any previous Loaders associated with
      * this ID will be considered invalid, and you will receive no further
      * data updates from them.
-     * 
+     *
      * @param id A unique (to this LoaderManager instance) identifier under
      * which to manage the new Loader.
      * @param args Optional arguments that will be propagated to
@@ -667,7 +667,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo info = mLoaders.get(id);
         if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
         if (info != null) {
@@ -706,7 +706,7 @@
                             info.mPendingLoader = null;
                         }
                         if (DEBUG) Log.v(TAG, "  Enqueuing as new pending loader");
-                        info.mPendingLoader = createLoader(id, args, 
+                        info.mPendingLoader = createLoader(id, args,
                                 (LoaderManager.LoaderCallbacks<Object>)callback);
                         return (Loader<D>)info.mPendingLoader.mLoader;
                     }
@@ -719,11 +719,11 @@
                 mInactiveLoaders.put(id, info);
             }
         }
-        
+
         info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
         return (Loader<D>)info.mLoader;
     }
-    
+
     /**
      * Rip down, tear apart, shred to pieces a current Loader ID.  After returning
      * from this function, any Loader objects associated with this ID are
@@ -735,7 +735,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
         int idx = mLoaders.indexOfKey(id);
         if (idx >= 0) {
@@ -763,7 +763,7 @@
         if (mCreatingLoader) {
             throw new IllegalStateException("Called while creating a loader");
         }
-        
+
         LoaderInfo loaderInfo = mLoaders.get(id);
         if (loaderInfo != null) {
             if (loaderInfo.mPendingLoader != null) {
@@ -773,16 +773,15 @@
         }
         return null;
     }
- 
+
     void doStart() {
         if (DEBUG) Log.v(TAG, "Starting in " + this);
         if (mStarted) {
             RuntimeException e = new RuntimeException("here");
-            e.fillInStackTrace();
             Log.w(TAG, "Called doStart when already started: " + this, e);
             return;
         }
-        
+
         mStarted = true;
 
         // Call out to sub classes so they can start their loaders
@@ -791,12 +790,11 @@
             mLoaders.valueAt(i).start();
         }
     }
-    
+
     void doStop() {
         if (DEBUG) Log.v(TAG, "Stopping in " + this);
         if (!mStarted) {
             RuntimeException e = new RuntimeException("here");
-            e.fillInStackTrace();
             Log.w(TAG, "Called doStop when not started: " + this, e);
             return;
         }
@@ -806,12 +804,11 @@
         }
         mStarted = false;
     }
-    
+
     void doRetain() {
         if (DEBUG) Log.v(TAG, "Retaining in " + this);
         if (!mStarted) {
             RuntimeException e = new RuntimeException("here");
-            e.fillInStackTrace();
             Log.w(TAG, "Called doRetain when not started: " + this, e);
             return;
         }
@@ -822,7 +819,7 @@
             mLoaders.valueAt(i).retain();
         }
     }
-    
+
     void finishRetain() {
         if (mRetaining) {
             if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);
@@ -833,7 +830,7 @@
             }
         }
     }
-    
+
     void doReportNextStart() {
         for (int i = mLoaders.size()-1; i >= 0; i--) {
             mLoaders.valueAt(i).mReportNextStart = true;
@@ -854,7 +851,7 @@
             }
             mLoaders.clear();
         }
-        
+
         if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
         for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
             mInactiveLoaders.valueAt(i).destroy();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0381ee0..cfe0ff9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -811,11 +811,20 @@
     }
 
     private static boolean isStandardLayout(int layoutId) {
+        // TODO: b/359128724 - Add to static list when inlining the flag.
         if (Flags.apiRichOngoing()) {
             if (layoutId == R.layout.notification_template_material_progress) {
                 return true;
             }
         }
+        // TODO: b/378660052 - Add to static list when inlining the flag.
+        if (Flags.notificationsRedesignTemplates()) {
+            switch(layoutId) {
+                case R.layout.notification_2025_template_collapsed_base:
+                case R.layout.notification_2025_template_header:
+                    return true;
+            }
+        }
         return STANDARD_LAYOUTS.contains(layoutId);
     }
 
@@ -5003,7 +5012,7 @@
 
         /**
          * Sets a very short string summarizing the most critical information contained in the
-         * notification. Suggested max length is 5 characters, and there is no guarantee how much or
+         * notification. Suggested max length is 7 characters, and there is no guarantee how much or
          * how little of this text will be shown.
          */
         @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
@@ -6718,7 +6727,7 @@
             // Headers on their own are never colorized
             p.disallowColorization();
             RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
-                    R.layout.notification_template_header);
+                    getHeaderLayoutResource());
             resetNotificationHeader(header);
             bindNotificationHeader(header, p);
             return header;
@@ -7478,9 +7487,21 @@
             return clone;
         }
 
+        private int getHeaderLayoutResource() {
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_header;
+            } else {
+                return R.layout.notification_template_header;
+            }
+        }
+
         @UnsupportedAppUsage
         private int getBaseLayoutResource() {
-            return R.layout.notification_template_material_base;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_collapsed_base;
+            } else {
+                return R.layout.notification_template_material_base;
+            }
         }
 
         private int getHeadsUpBaseLayoutResource() {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 1dc7742..675152f 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1947,10 +1947,12 @@
     }
 
     // Return true if this cache has had any activity.  If the hits, misses, and skips are all
-    // zero then the client never tried to use the cache.
-    private boolean isActive() {
+    // zero then the client never tried to use the cache.  If invalidations and corks are also
+    // zero then the server never tried to use the cache.
+    private boolean isActive(NonceHandler.Stats stats) {
         synchronized (mLock) {
-            return mHits + mMisses + getSkipsLocked() > 0;
+            return mHits + mMisses + getSkipsLocked()
+                    + stats.invalidated + stats.corkedInvalidates > 0;
         }
     }
 
@@ -1968,15 +1970,15 @@
         NonceHandler.Stats stats = mNonce.getStats();
 
         synchronized (mLock) {
-            if (brief && !isActive()) {
+            if (brief && !isActive(stats)) {
                 return;
             }
 
             pw.println(formatSimple("  Cache Name: %s", cacheName()));
             pw.println(formatSimple("    Property: %s", mPropertyName));
             pw.println(formatSimple(
-                "    Hits: %d, Misses: %d, Skips: %d, Clears: %d, Uids: %d",
-                mHits, mMisses, getSkipsLocked(), mClears, mCache.size()));
+                "    Hits: %d, Misses: %d, Skips: %d, Clears: %d",
+                mHits, mMisses, getSkipsLocked(), mClears));
 
             // Print all the skip reasons.
             pw.format("    Skip-%s: %d", sNonceName[0], mSkips[0]);
@@ -1986,7 +1988,7 @@
             pw.println();
 
             pw.println(formatSimple(
-                "    Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
+                "    Nonce: 0x%016x, Invalidates: %d, Corked: %d",
                 mLastSeenNonce, stats.invalidated, stats.corkedInvalidates));
             pw.println(formatSimple(
                 "    Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index f702b85..087e246 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1186,7 +1186,6 @@
         synchronized (mLock) {
             if (DEBUG) {
                 Throwable here = new Throwable();
-                here.fillInStackTrace();
                 Slog.w(TAG, "!! Create resources for key=" + key, here);
             }
 
@@ -1207,7 +1206,6 @@
         synchronized (mLock) {
             if (DEBUG) {
                 Throwable here = new Throwable();
-                here.fillInStackTrace();
                 Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
             }
 
@@ -1351,7 +1349,6 @@
 
                 if (DEBUG) {
                     Throwable here = new Throwable();
-                    here.fillInStackTrace();
                     Slog.d(TAG, "updating resources override for activity=" + activityToken
                             + " from oldConfig="
                             + Configuration.resourceQualifierString(oldConfig)
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e451116..53a7dad 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
+import static android.provider.flags.Flags.stageFlagsForBuild;
 import static android.server.Flags.removeGameManagerServiceFromWear;
 
 import android.accounts.AccountManager;
@@ -163,6 +164,7 @@
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.nearby.NearbyFrameworkInitializer;
 import android.net.ConnectivityFrameworkInitializer;
+import android.net.ConnectivityFrameworkInitializerBaklava;
 import android.net.ConnectivityFrameworkInitializerTiramisu;
 import android.net.INetworkPolicyManager;
 import android.net.IPacProxyManager;
@@ -173,7 +175,6 @@
 import android.net.PacProxyManager;
 import android.net.TetheringManager;
 import android.net.VpnManager;
-import android.net.vcn.VcnFrameworkInitializer;
 import android.net.wifi.WifiFrameworkInitializer;
 import android.net.wifi.nl80211.WifiNl80211Manager;
 import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
@@ -190,6 +191,7 @@
 import android.os.IBinder;
 import android.os.IDumpstate;
 import android.os.IHardwarePropertiesManager;
+import android.os.IHintManager;
 import android.os.IPowerManager;
 import android.os.IPowerStatsService;
 import android.os.IRecoverySystem;
@@ -215,6 +217,7 @@
 import android.os.UserManager;
 import android.os.Vibrator;
 import android.os.VibratorManager;
+import android.os.flagging.ConfigInfrastructureFrameworkInitializer;
 import android.os.health.SystemHealthManager;
 import android.os.image.DynamicSystemManager;
 import android.os.image.IDynamicSystemService;
@@ -238,6 +241,8 @@
 import android.security.advancedprotection.IAdvancedProtectionService;
 import android.security.attestationverification.AttestationVerificationManager;
 import android.security.attestationverification.IAttestationVerificationManagerService;
+import android.security.forensic.ForensicManager;
+import android.security.forensic.IForensicService;
 import android.security.keystore.KeyStoreManager;
 import android.service.oemlock.IOemLockService;
 import android.service.oemlock.OemLockManager;
@@ -1195,8 +1200,10 @@
             public SystemHealthManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                 IBinder batteryStats = ServiceManager.getServiceOrThrow(BatteryStats.SERVICE_NAME);
                 IBinder powerStats = ServiceManager.getService(Context.POWER_STATS_SERVICE);
+                IBinder perfHint = ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE);
                 return new SystemHealthManager(IBatteryStats.Stub.asInterface(batteryStats),
-                        IPowerStatsService.Stub.asInterface(powerStats));
+                        IPowerStatsService.Stub.asInterface(powerStats),
+                        IHintManager.Stub.asInterface(perfHint));
             }});
 
         registerService(Context.CONTEXTHUB_SERVICE, ContextHubManager.class,
@@ -1790,6 +1797,18 @@
                     }
                 });
 
+        registerService(Context.FORENSIC_SERVICE, ForensicManager.class,
+                new CachedServiceFetcher<ForensicManager>() {
+                    @Override
+                    public ForensicManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.FORENSIC_SERVICE);
+                        IForensicService service = IForensicService.Stub.asInterface(b);
+                        return new ForensicManager(service);
+                    }
+                });
+
         sInitializing = true;
         try {
             // Note: the following functions need to be @SystemApis, once they become mainline
@@ -1818,7 +1837,11 @@
             OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
             DeviceLockFrameworkInitializer.registerServiceWrappers();
             VirtualizationFrameworkInitializer.registerServiceWrappers();
-            VcnFrameworkInitializer.registerServiceWrappers();
+            ConnectivityFrameworkInitializerBaklava.registerServiceWrappers();
+
+            if (stageFlagsForBuild()) {
+                ConfigInfrastructureFrameworkInitializer.registerServiceWrappers();
+            }
 
             if (com.android.server.telecom.flags.Flags.telecomMainlineBlockedNumbersManager()) {
                 ProviderFrameworkInitializer.registerServiceWrappers();
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 637187e..5ed1f4e 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -177,10 +177,6 @@
         {
             "file_patterns": ["(/|^)AppOpsManager.java"],
             "name": "CtsAppOpsTestCases"
-        },
-        {
-            "file_patterns": ["(/|^)BroadcastStickyCache.java"],
-            "name": "BroadcastUnitTests"
         }
     ]
 }
diff --git a/core/java/android/app/ZenBypassingApp.java b/core/java/android/app/ZenBypassingApp.java
new file mode 100644
index 0000000..89bcfa2
--- /dev/null
+++ b/core/java/android/app/ZenBypassingApp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class ZenBypassingApp implements Parcelable {
+
+    @NonNull private String mPkg;
+    private boolean mAllChannelsBypass;
+
+
+    public ZenBypassingApp(@NonNull String pkg, boolean allChannelsBypass) {
+        mPkg = pkg;
+        mAllChannelsBypass = allChannelsBypass;
+    }
+
+    public ZenBypassingApp(Parcel source) {
+        mPkg = source.readString();
+        mAllChannelsBypass = source.readBoolean();
+    }
+
+    @NonNull
+    public String getPkg() {
+        return mPkg;
+    }
+
+    public boolean doAllChannelsBypass() {
+        return mAllChannelsBypass;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mPkg);
+        dest.writeBoolean(mAllChannelsBypass);
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<ZenBypassingApp> CREATOR
+            = new Parcelable.Creator<ZenBypassingApp>() {
+        @Override
+        public ZenBypassingApp createFromParcel(Parcel source) {
+            return new ZenBypassingApp(source);
+        }
+        @Override
+        public ZenBypassingApp[] newArray(int size) {
+            return new ZenBypassingApp[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ZenBypassingApp)) return false;
+        ZenBypassingApp that = (ZenBypassingApp) o;
+        return mAllChannelsBypass == that.mAllChannelsBypass && Objects.equals(mPkg,
+                that.mPkg);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPkg, mAllChannelsBypass);
+    }
+
+    @Override
+    public String toString() {
+        return "ZenBypassingApp{" +
+                "mPkg='" + mPkg + '\'' +
+                ", mAllChannelsBypass=" + mAllChannelsBypass +
+                '}';
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bff77f9..e766ae2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,7 @@
 
 package android.app.admin;
 
+import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.LOCK_DEVICE;
@@ -8920,12 +8921,9 @@
     /**
      * Called by a device owner, a profile owner for the primary user or a profile
      * owner of an organization-owned managed profile to turn auto time on and off.
-     * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
-     * to prevent the user from changing this setting.
      * <p>
-     * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used,
-     * no user will be able set the date and time. Instead, the network date
-     * and time will be used.
+     * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+     * user from changing this setting, that way no user will be able set the date and time zone.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
      *              caller is not a device admin.
@@ -8938,7 +8936,13 @@
         throwIfParentInstance("setAutoTimeEnabled");
         if (mService != null) {
             try {
-                mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
+                if (Flags.setAutoTimeEnabledCoexistence()) {
+                    mService.setAutoTimePolicy(mContext.getPackageName(),
+                            enabled ? DevicePolicyManager.AUTO_TIME_ENABLED
+                                    : DevicePolicyManager.AUTO_TIME_DISABLED);
+                } else {
+                    mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
+                }
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -8968,6 +8972,97 @@
     }
 
     /**
+     * Specifies that the auto time state is not controlled by device policy.
+     *
+     * @see #setAutoTimePolicy(ComponentName, int)
+     */
+    @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+    public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0;
+
+    /**
+     * Specifies the "disabled" auto time state.
+     *
+     * @see #setAutoTimePolicy(ComponentName, int)
+     */
+    @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+    public static final int AUTO_TIME_DISABLED = 1;
+
+    /**
+     * Specifies the "enabled" auto time state.
+     *
+     * @see #setAutoTimePolicy(ComponentName, int)
+     */
+    @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+    public static final int AUTO_TIME_ENABLED = 2;
+
+    /**
+     * Flags supplied to {@link #setAutoTimePolicy}(ComponentName, int)}.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "AUTO_TIME_" }, value = {
+            AUTO_TIME_NOT_CONTROLLED_BY_POLICY,
+            AUTO_TIME_DISABLED,
+            AUTO_TIME_ENABLED
+    })
+    public @interface AutoTimePolicy {}
+
+    /**
+     * Called by a device owner, a profile owner for the primary user or a profile owner of an
+     * organization-owned managed profile to turn auto time on and off i.e. Whether time should be
+     * obtained automatically from the network or not.
+     * <p>
+     * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the
+     * user from changing this setting, that way no user will be able set the date and time zone.
+     *
+     * @param policy The desired state among {@link #AUTO_TIME_ENABLED} to enable,
+     *              {@link #AUTO_TIME_DISABLED} to disable and
+     *              {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} to unset the policy.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile, or if the caller
+     * does not hold the required permission.
+     */
+    @SupportsCoexistence
+    @RequiresPermission(value = SET_TIME, conditional = true)
+    @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+    public void setAutoTimePolicy(@AutoTimePolicy int policy) {
+        throwIfParentInstance("setAutoTimePolicy");
+        if (mService != null) {
+            try {
+                mService.setAutoTimePolicy(mContext.getPackageName(), policy);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns current auto time policy's state.
+     *
+     * @return One of {@link #AUTO_TIME_ENABLED} if enabled, {@link #AUTO_TIME_DISABLED} if disabled
+     *              and {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} if it's not controlled by
+     *              policy.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile, or if the caller
+     * does not hold the required permission.
+     */
+    @SupportsCoexistence
+    @RequiresPermission(anyOf = {SET_TIME, QUERY_ADMIN_POLICY}, conditional = true)
+    @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE)
+    public @AutoTimePolicy int getAutoTimePolicy() {
+        throwIfParentInstance("getAutoTimePolicy");
+        if (mService != null) {
+            try {
+                return mService.getAutoTimePolicy(mContext.getPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
+    }
+
+    /**
      * Called by a device owner, a profile owner for the primary user or a profile
      * owner of an organization-owned managed profile to turn auto time zone on and off.
      * <p>
@@ -12102,6 +12197,33 @@
     }
 
     /**
+     * Adds a user restriction globally, specified by the {@code key}.
+     *
+     * <p>Called by a system service only, meaning that the caller's UID must be equal to
+     * {@link Process#SYSTEM_UID}.
+     *
+     * @param systemEntity The service entity that adds the restriction. A user restriction set by
+     *                     a service entity can only be cleared by the same entity. This can be
+     *                     just the calling package name, or any string of the caller's choice
+     *                     can be used.
+     * @param key The key of the restriction.
+     * @throws SecurityException if the caller is not a system service.
+     *
+     * @hide
+     */
+    public void addUserRestrictionGlobally(@NonNull String systemEntity,
+            @NonNull @UserManager.UserRestrictionKey String key) {
+        if (mService != null) {
+            try {
+                mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
+                        /* enable= */ true);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Called by a profile owner, device owner or a holder of any permission that is associated with
      * a user restriction to clear a user restriction specified by the key.
      * <p>
@@ -12187,6 +12309,33 @@
     }
 
     /**
+     * Clears a user restriction globally, specified by the {@code key}.
+     *
+     * <p>Called by a system service only, meaning that the caller's UID must be equal to
+     * {@link Process#SYSTEM_UID}.
+     *
+     * @param systemEntity The system entity that clears the restriction. A user restriction
+     *                     set by a system entity can only be cleared by the same entity. This
+     *                     can be just the calling package name, or any string of the caller's
+     *                     choice can be used.
+     * @param key The key of the restriction.
+     * @throws SecurityException if the caller is not a system service.
+     *
+     * @hide
+     */
+    public void clearUserRestrictionGlobally(@NonNull String systemEntity,
+            @NonNull @UserManager.UserRestrictionKey String key) {
+        if (mService != null) {
+            try {
+                mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
+                        /* enable= */ false);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Called by an admin to get user restrictions set by themselves with
      * {@link #addUserRestriction(ComponentName, String)}.
      * <p>
@@ -17048,11 +17197,14 @@
      * @throws SecurityException if the caller does not hold
      * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
      * @throws ProvisioningException if an error occurred during provisioning.
+     * @deprecated Use {@link #createManagedProfile} and {@link #finalizeCreateManagedProfile}
      * @hide
      */
     @Nullable
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
     public UserHandle createAndProvisionManagedProfile(
             @NonNull ManagedProfileProvisioningParams provisioningParams)
             throws ProvisioningException {
@@ -17070,6 +17222,69 @@
     }
 
     /**
+     * Creates a managed profile and sets the
+     * {@link ManagedProfileProvisioningParams#getProfileAdminComponentName()} as the profile
+     * owner. The method {@link #finalizeCreateManagedProfile} must be called after to finalize the
+     * creation of the managed profile.
+     *
+     * <p>The method {@link #checkProvisioningPrecondition} must return {@link #STATUS_OK}
+     * before calling this method. If it doesn't, a ProvisioningException will be thrown.
+     *
+     * @param provisioningParams Params required to provision a managed profile,
+     * see {@link ManagedProfileProvisioningParams}.
+     * @return The {@link UserHandle} of the created profile or {@code null} if the service is
+     * not available.
+     * @throws ProvisioningException if an error occurred during provisioning.
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+    public UserHandle createManagedProfile(
+            @NonNull ManagedProfileProvisioningParams provisioningParams)
+            throws ProvisioningException {
+        if (mService == null) {
+            return null;
+        }
+        try {
+            return mService.createManagedProfile(provisioningParams, mContext.getPackageName());
+        } catch (ServiceSpecificException e) {
+            throw new ProvisioningException(e, e.errorCode, getErrorMessage(e));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Finalizes the creation of a managed profile by informing the necessary components that
+     * the managed profile is ready.
+     *
+     * @param provisioningParams Params required to provision a managed profile,
+     * see {@link ManagedProfileProvisioningParams}.
+     * @param managedProfileUser The recently created managed profile.
+     * @throws ProvisioningException if an error occurred during provisioning.
+     * @hide
+     */
+    @SuppressLint("UserHandle")
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+    public void finalizeCreateManagedProfile(
+            @NonNull ManagedProfileProvisioningParams provisioningParams,
+            @NonNull UserHandle managedProfileUser)
+            throws ProvisioningException {
+        if (mService == null) {
+            return;
+        }
+        try {
+            mService.finalizeCreateManagedProfile(provisioningParams, managedProfileUser);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Removes a manged profile from the device only when called from a managed profile's context
      *
      * @param user UserHandle of the profile to be removed
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0b8f538..d048b53 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -257,6 +257,7 @@
     void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
     void setUserRestrictionForUser(in String systemEntity, in String key, boolean enable, int targetUser);
     void setUserRestrictionGlobally(in String callerPackage, in String key);
+    void setUserRestrictionGloballyFromSystem(in String systemEntity, in String key, boolean enable);
     Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
     Bundle getUserRestrictionsGlobally(in String callerPackage);
 
@@ -375,6 +376,9 @@
     void setAutoTimeEnabled(in ComponentName who, String callerPackageName, boolean enabled);
     boolean getAutoTimeEnabled(in ComponentName who, String callerPackageName);
 
+    void setAutoTimePolicy(String callerPackageName, int policy);
+    int getAutoTimePolicy(String callerPackageName);
+
     void setAutoTimeZoneEnabled(in ComponentName who, String callerPackageName, boolean enabled);
     boolean getAutoTimeZoneEnabled(in ComponentName who, String callerPackageName);
 
@@ -566,6 +570,8 @@
     void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId);
 
     UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
+    UserHandle createManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
+    void finalizeCreateManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in UserHandle managedProfileUser);
     void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
 
     void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 404471e..581efa5 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -343,6 +343,16 @@
 }
 
 flag {
+    name: "active_admin_cleanup"
+    namespace: "enterprise"
+    description: "Remove ActiveAdmin from EnforcingAdmin and related cleanups"
+    bug: "335663055"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "user_provisioning_same_state"
     namespace: "enterprise"
     description: "Handle exceptions while setting same provisioning state."
@@ -372,7 +382,7 @@
     is_exported: true
     namespace: "enterprise"
     description: "Allows DPMS to enable or disable SupervisionService based on whether the device is being managed by the supervision role holder."
-    bug: "376213673"
+    bug: "358134581"
 }
 
 flag {
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index dcac59c..5004c02 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,8 @@
 
 package android.app.backup;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Intent;
@@ -27,6 +29,7 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.backup.ITransportStatusCallback;
 import com.android.internal.infra.AndroidFuture;
+import com.android.server.backup.Flags;
 
 import java.util.Arrays;
 import java.util.List;
@@ -671,6 +674,22 @@
     }
 
     /**
+     * Ask the transport whether packages that are about to be backed up or restored should not be
+     * put into a restricted mode by the framework and started normally instead.
+     *
+     * @param operationType 0 for backup, 1 for restore.
+     * @return a subset of the {@code packageNames} passed in, indicating
+     * which packages should NOT be put into restricted mode for the given operation type.
+     */
+    @NonNull
+    @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public List<String> getPackagesThatShouldNotUseRestrictedMode(
+            @NonNull List<String> packageNames,
+            @BackupAnnotations.OperationType int operationType) {
+        return List.of();
+    }
+
+    /**
      * Bridge between the actual IBackupTransport implementation and the stable API.  If the
      * binder interface needs to change, we use this layer to translate so that we can
      * (if appropriate) decouple those framework-side changes from the BackupTransport
@@ -977,5 +996,19 @@
                 resultFuture.cancel(/* mayInterruptIfRunning */ true);
             }
         }
+
+        @Override
+        @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+        public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames,
+                int operationType, AndroidFuture<List<String>> resultFuture) {
+            try {
+                List<String> result =
+                        BackupTransport.this.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+                                operationType);
+                resultFuture.complete(result);
+            } catch (RuntimeException e) {
+                resultFuture.cancel(/* mayInterruptIfRunning */ true);
+            }
+        }
     }
 }
diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java
index 3783a5f..7525d04 100644
--- a/core/java/android/app/jank/JankDataProcessor.java
+++ b/core/java/android/app/jank/JankDataProcessor.java
@@ -70,8 +70,8 @@
             for (int j = 0; j < mPendingStates.size(); j++) {
                 StateData pendingState = mPendingStates.get(j);
                 // This state was active during the frame
-                if (frame.frameVsyncId >= pendingState.mVsyncIdStart
-                        && frame.frameVsyncId <= pendingState.mVsyncIdEnd) {
+                if (frame.getVsyncId() >= pendingState.mVsyncIdStart
+                        && frame.getVsyncId() <= pendingState.mVsyncIdEnd) {
                     recordFrameCount(frame, pendingState, activityName, appUid);
 
                     pendingState.mProcessed = true;
@@ -131,14 +131,14 @@
             mPendingJankStats.put(stateData.mStateDataKey, jankStats);
         }
         // This state has already been accounted for
-        if (jankStats.processedVsyncId == frameData.frameVsyncId) return;
+        if (jankStats.processedVsyncId == frameData.getVsyncId()) return;
 
         jankStats.mTotalFrames += 1;
-        if (frameData.jankType == JankData.JANK_APPLICATION) {
+        if ((frameData.getJankType() & JankData.JANK_APPLICATION) != 0) {
             jankStats.mJankyFrames += 1;
         }
-        jankStats.recordFrameOverrun(frameData.actualAppFrameTimeNs);
-        jankStats.processedVsyncId = frameData.frameVsyncId;
+        jankStats.recordFrameOverrun(frameData.getActualAppFrameTimeNanos());
+        jankStats.processedVsyncId = frameData.getVsyncId();
 
     }
 
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 6934e98..2e3d5e1 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -13,6 +13,13 @@
 }
 
 flag {
+  name: "notifications_redesign_templates"
+  namespace: "systemui"
+  description: "Notifications Redesign: Update notification templates"
+  bug: "378660052"
+}
+
+flag {
   name: "modes_api"
   is_exported: true
   namespace: "systemui"
@@ -268,3 +275,10 @@
   description: "Adds UI for NAS classification of notifications"
   bug: "367996732"
 }
+
+flag {
+  name: "no_sbnholder"
+  namespace: "systemui"
+  description: "removes sbnholder from NLS"
+  bug: "362981561"
+}
diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
index 8b6441a..74a96c8 100644
--- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
+++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig
@@ -8,3 +8,10 @@
     description: "Make methods on OnDeviceIntelligenceManager available for local inference."
     bug: "304755128"
 }
+flag {
+    name: "enable_on_device_intelligence_module"
+    is_exported: true
+    namespace: "ondeviceintelligence"
+    description: "Enable migration to mainline module and related changes."
+    bug: "376427781"
+}
\ No newline at end of file
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java b/core/java/android/app/supervision/SupervisionManagerInternal.java
similarity index 84%
rename from services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java
rename to core/java/android/app/supervision/SupervisionManagerInternal.java
index 5df9dd5..d571e14 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java
+++ b/core/java/android/app/supervision/SupervisionManagerInternal.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.supervision;
+package android.app.supervision;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.os.Bundle;
+import android.os.PersistableBundle;
 
 /**
  * Local system service interface for {@link SupervisionService}.
@@ -35,6 +35,11 @@
     public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId);
 
     /**
+     * Returns whether the supervision lock screen needs to be shown.
+     */
+    public abstract boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId);
+
+    /**
      * Set whether supervision is enabled for the specified user.
      *
      * @param userId The user to set the supervision state for
@@ -50,5 +55,5 @@
      * @param options Optional configuration parameters for the supervision lock screen
      */
     public abstract void setSupervisionLockscreenEnabledForUser(
-            @UserIdInt int userId, boolean enabled, @Nullable Bundle options);
+            @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options);
 }
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index ce51576..fb33348 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -92,3 +92,13 @@
   is_exported: true
   is_fixed_read_only: true
 }
+
+flag {
+  name: "check_remote_views_uri_permission"
+  namespace: "app_widgets"
+  description: "Check that the widget provider has permissions to access any URIs within its RemoteViews"
+  bug: "369137473"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index c47fe23..de01280 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -148,6 +148,14 @@
 
 flag {
     namespace: "virtual_devices"
+    name: "notifications_for_device_streaming"
+    description: "Add notifications permissions to device streaming role"
+    bug: "375240276"
+    is_exported: true
+}
+
+flag {
+    namespace: "virtual_devices"
     name: "default_device_camera_access_policy"
     description: "API for default device camera access policy"
     bug: "371173368"
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 964a8be..a816294 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -356,7 +356,6 @@
             }
             RuntimeException e = new RuntimeException(
                     "BroadcastReceiver trying to return result during a non-ordered broadcast");
-            e.fillInStackTrace();
             Log.e("BroadcastReceiver", e.getMessage(), e);
         }
     }
@@ -768,7 +767,6 @@
         }
         RuntimeException e = new RuntimeException(
                 "BroadcastReceiver trying to return result during a non-ordered broadcast");
-        e.fillInStackTrace();
         Log.e("BroadcastReceiver", e.getMessage(), e);
     }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b776b59..8853304 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -87,7 +87,6 @@
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.expresslog.Counter;
 
@@ -12304,7 +12303,6 @@
     }
 
     /** @hide */
-    @VisibleForTesting
     public Set<NestedIntentKey> getExtraIntentKeys() {
         return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mNestedIntentKeys;
     }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3152ff4..37295ac 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -193,6 +193,42 @@
             "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES";
 
     /**
+     * &lt;application&gt; level {@link android.content.pm.PackageManager.Property} tag
+     * specifying whether the app should be put into the "restricted" backup mode when it's started
+     * for backup and restore operations.
+     *
+     * <p> See <a
+     * href="https://developer.android.com/identity/data/autobackup#ImplementingBackupAgent"> for
+     * information about restricted mode</a>.
+     *
+     * <p> Starting with Android 16 apps may not be started in restricted mode based on this
+     * property.
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE"
+     *     android:value="true|false"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     *
+     * <p>If this property is set, the operating system will respect it for now (see Note below).
+     * If it's not set, the behavior depends on the SDK level that the app is targeting. For apps
+     * targeting SDK level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or lower, the
+     * property defaults to {@code true}. For apps targeting SDK level
+     * {@link android.os.Build.VERSION_CODES#BAKLAVA} or higher, the operating system will make a
+     * decision dynamically.
+     *
+     * <p>Note: It's not recommended to set this property to {@code true} unless absolutely
+     * necessary. In a future Android version, this property may be deprecated in favor of removing
+     * restricted mode completely.
+     */
+    @FlaggedApi(com.android.server.backup.Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE =
+            "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE";
+
+    /**
      * Application level property that an app can specify to opt-out from having private data
      * directories both on the internal and external storages.
      *
@@ -292,6 +328,10 @@
      * <p>
      * The value of a property will only have a single type, as defined by
      * the property itself.
+     *
+     * <p class="note"><strong>Note:</strong>
+     * In android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and earlier,
+     * the {@code equals} and {@code hashCode} methods for this class may not function as expected.
      */
     public static final class Property implements Parcelable {
         private static final int TYPE_BOOLEAN = 1;
@@ -523,6 +563,40 @@
                 return new Property[size];
             }
         };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Property)) {
+                return false;
+            }
+            final Property property = (Property) obj;
+            return mType == property.mType &&
+                    Objects.equals(mName, property.mName) &&
+                    Objects.equals(mClassName, property.mClassName) &&
+                    Objects.equals(mPackageName, property.mPackageName) &&
+                    (mType == TYPE_BOOLEAN ? mBooleanValue == property.mBooleanValue :
+                     mType == TYPE_FLOAT ? Float.compare(mFloatValue, property.mFloatValue) == 0 :
+                     mType == TYPE_INTEGER ? mIntegerValue == property.mIntegerValue :
+                     mType == TYPE_RESOURCE ? mIntegerValue == property.mIntegerValue :
+                     mStringValue.equals(property.mStringValue));
+        }
+
+        @Override
+        public int hashCode() {
+            int result = Objects.hash(mName, mType, mClassName, mPackageName);
+            if (mType == TYPE_BOOLEAN) {
+                result = 31 * result + (mBooleanValue ? 1 : 0);
+            } else if (mType == TYPE_FLOAT) {
+                result = 31 * result + Float.floatToIntBits(mFloatValue);
+            } else if (mType == TYPE_INTEGER) {
+                result = 31 * result + mIntegerValue;
+            } else if (mType == TYPE_RESOURCE) {
+                result = 31 * result + mIntegerValue;
+            } else if (mType == TYPE_STRING) {
+                result = 31 * result + mStringValue.hashCode();
+            }
+            return result;
+        }
     }
 
     /**
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index f7191e6..5dfec98 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -105,6 +105,8 @@
     private final List<VersionedPackage> mOptionalDependentPackages;
     private List<SharedLibraryInfo> mDependencies;
 
+    private final List<String> mCertDigests;
+
     /**
      * Creates a new instance.
      *
@@ -134,6 +136,7 @@
         mDependencies = dependencies;
         mIsNative = isNative;
         mOptionalDependentPackages = null;
+        mCertDigests = null;
     }
 
     /**
@@ -165,6 +168,7 @@
         mDeclaringPackage = declaringPackage;
         mDependencies = dependencies;
         mIsNative = isNative;
+        mCertDigests = null;
 
         var allDependents = allDependentPackages.first;
         var usesLibOptional = allDependentPackages.second;
@@ -206,6 +210,7 @@
         mIsNative = parcel.readBoolean();
         mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
                 VersionedPackage.class.getClassLoader(), VersionedPackage.class);
+        mCertDigests = parcel.createStringArrayList();
     }
 
     /**
@@ -214,6 +219,7 @@
      * @param versionMajor
      */
     public SharedLibraryInfo(String name, long versionMajor, int type) {
+        //TODO: change to this(name, versionMajor, type, /* certDigest= */null); after flag removal
         mPath = null;
         mPackageName = null;
         mName = name;
@@ -224,6 +230,29 @@
         mDependencies = null;
         mIsNative = false;
         mOptionalDependentPackages = null;
+        mCertDigests = null;
+    }
+
+    /**
+     * @hide
+     * @param name The lib name.
+     * @param versionMajor The lib major version.
+     * @param type The type of shared library.
+     * @param certDigests The list of certificate digests for this shared library.
+     */
+    @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+    public SharedLibraryInfo(String name, long versionMajor, int type, List<String> certDigests) {
+        mPath = null;
+        mPackageName = null;
+        mName = name;
+        mVersion = versionMajor;
+        mType = type;
+        mDeclaringPackage = null;
+        mDependentPackages = null;
+        mDependencies = null;
+        mIsNative = false;
+        mOptionalDependentPackages = null;
+        mCertDigests = certDigests;
     }
 
     /**
@@ -433,6 +462,19 @@
         return mOptionalDependentPackages;
     }
 
+    /**
+     * Gets the list of certificate digests for the shared library.
+     *
+     * @return The list of certificate digests
+     */
+    @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+    public @NonNull List<String> getCertDigests() {
+        if (mCertDigests == null) {
+            return Collections.emptyList();
+        }
+        return mCertDigests;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -463,6 +505,7 @@
         parcel.writeTypedList(mDependencies);
         parcel.writeBoolean(mIsNative);
         parcel.writeParcelableList(mOptionalDependentPackages, flags);
+        parcel.writeStringList(mCertDigests);
     }
 
     private static String typeToString(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
similarity index 75%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
index e4ccc2c..06fcabc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.content.pm.dependencyinstaller;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+parcelable DependencyInstallerCallback;
\ No newline at end of file
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
new file mode 100644
index 0000000..ba089f7
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.dependencyinstaller;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.pm.Flags;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * Callbacks for {@link DependencyInstallerService}. The implementation of
+ * DependencyInstallerService uses this interface to indicate completion of the session creation
+ * request given by the system server.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+public final class DependencyInstallerCallback implements Parcelable {
+    private final IBinder mBinder;
+    private final IDependencyInstallerCallback mCallback;
+
+    /** @hide */
+    public DependencyInstallerCallback(IBinder binder) {
+        mBinder = binder;
+        mCallback = IDependencyInstallerCallback.Stub.asInterface(binder);
+    }
+
+    private DependencyInstallerCallback(Parcel in) {
+        mBinder = in.readStrongBinder();
+        mCallback = IDependencyInstallerCallback.Stub.asInterface(mBinder);
+    }
+
+    /**
+     * Callback to indicate that all the requested dependencies have been resolved and their
+     * sessions created. See {@link  DependencyInstallerService#onDependenciesRequired}.
+     *
+     * @param sessionIds the install session IDs for all requested dependencies
+     */
+    public void onAllDependenciesResolved(@NonNull int[] sessionIds) {
+        try {
+            mCallback.onAllDependenciesResolved(sessionIds);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to indicate that at least one of the required dependencies could not be resolved
+     * and any associated sessions have been abandoned.
+     */
+    public void onFailureToResolveAllDependencies() {
+        try {
+            mCallback.onFailureToResolveAllDependencies();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeStrongBinder(mBinder);
+    }
+
+    public static final @NonNull Creator<DependencyInstallerCallback> CREATOR =
+            new Creator<>() {
+                @Override
+                public DependencyInstallerCallback createFromParcel(Parcel in) {
+                    return new DependencyInstallerCallback(in);
+                }
+
+                @Override
+                public DependencyInstallerCallback[] newArray(int size) {
+                    return new DependencyInstallerCallback[size];
+                }
+            };
+}
diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java
new file mode 100644
index 0000000..1186415
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.dependencyinstaller;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.Flags;
+import android.content.pm.SharedLibraryInfo;
+import android.os.IBinder;
+
+import java.util.List;
+
+/**
+ * Service that needs to be implemented by the holder of the DependencyInstaller role. This service
+ * will be invoked by the system during application installations if it depends on
+ * {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or
+ * {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE} and those dependencies aren't
+ * already installed.
+ * <p>
+ * Below is an example manifest registration for a {@code DependencyInstallerService}.
+ * <pre>
+ * {@code
+ * <service android:name=".ExampleDependencyInstallerService"
+ *     android:permission="android.permission.BIND_DEPENDENCY_INSTALLER" >
+ *     ...
+ *     <intent-filter>
+ *         <action android:name="android.content.pm.action.INSTALL_DEPENDENCY" />
+ *     </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+public abstract class DependencyInstallerService extends Service {
+
+    private IDependencyInstallerService mBinder;
+
+    @Override
+    public final @NonNull IBinder onBind(@Nullable Intent intent) {
+        if (mBinder == null) {
+            mBinder = new IDependencyInstallerService.Stub() {
+                @Override
+                public void onDependenciesRequired(List<SharedLibraryInfo> neededLibraries,
+                        DependencyInstallerCallback callback) {
+                    DependencyInstallerService.this.onDependenciesRequired(neededLibraries,
+                            callback);
+                }
+            };
+        }
+        return mBinder.asBinder();
+    }
+
+    /**
+     * Notify the holder of the DependencyInstaller role of the missing dependencies required for
+     * the completion of an active install session.
+     *
+     * @param neededLibraries the list of shared library dependencies needed to be obtained and
+     *                        installed.
+     */
+    public abstract void onDependenciesRequired(@NonNull List<SharedLibraryInfo> neededLibraries,
+            @NonNull DependencyInstallerCallback callback);
+}
diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
new file mode 100644
index 0000000..92d1d9e
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.dependencyinstaller;
+
+import java.util.List;
+
+/**
+* Callbacks for Dependency Installer. The app side invokes on this interface to indicate
+* completion of the async dependency install request given by the system server.
+*
+* {@hide}
+*/
+oneway interface IDependencyInstallerCallback {
+    /**
+     * Callback to indicate that all the requested dependencies have been resolved and have been
+     * committed for installation. See {@link  DependencyInstallerService#onDependenciesRequired}.
+     *
+     * @param sessionIds the install session IDs for all requested dependencies
+     */
+    void onAllDependenciesResolved(in int[] sessionIds);
+
+    /**
+     * Callback to indicate that at least one of the required dependencies could not be resolved
+     * and any associated sessions have been abandoned.
+     */
+    void onFailureToResolveAllDependencies();
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl
new file mode 100644
index 0000000..94f5bf4
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.dependencyinstaller;
+
+import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
+import android.content.pm.SharedLibraryInfo;
+import java.util.List;
+
+/**
+* Interface used to communicate with the application code that holds the Dependency Installer role.
+* {@hide}
+*/
+oneway interface IDependencyInstallerService {
+    /**
+     * Notify dependency installer of the required dependencies to complete the current install
+     * session.
+     *
+     * @param neededLibraries the list of shared library dependencies needed to be obtained and
+     *                        installed.
+     */
+    void onDependenciesRequired(in List<SharedLibraryInfo> neededLibraries,
+                in DependencyInstallerCallback callback);
+ }
\ No newline at end of file
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 9ba5a35..e181ae8 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -366,3 +366,13 @@
     description: "Block app installations that specify an incompatible minor SDK version"
     bug: "377474232"
 }
+
+flag {
+    name: "app_compat_option_16kb"
+    is_exported: true
+    namespace: "devoptions_settings"
+    description: "Feature flag to enable page size app compat mode from manifest, package manager and settings level."
+    bug: "371049373"
+    is_fixed_read_only: true
+}
+
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 6fd4d01..4551bd5 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -973,9 +973,9 @@
      * Open an asset using ACCESS_STREAMING mode.  This provides access to
      * files that have been bundled with an application as assets -- that is,
      * files placed in to the "assets" directory.
-     * 
+     *
      * @param fileName The name of the asset to open.  This name can be hierarchical.
-     * 
+     *
      * @see #open(String, int)
      * @see #list
      */
@@ -988,10 +988,10 @@
      * read its contents.  This provides access to files that have been bundled
      * with an application as assets -- that is, files placed in to the
      * "assets" directory.
-     * 
+     *
      * @param fileName The name of the asset to open.  This name can be hierarchical.
      * @param accessMode Desired access mode for retrieving the data.
-     * 
+     *
      * @see #ACCESS_UNKNOWN
      * @see #ACCESS_STREAMING
      * @see #ACCESS_RANDOM
@@ -1037,14 +1037,14 @@
 
     /**
      * Return a String array of all the assets at the given path.
-     * 
+     *
      * @param path A relative path within the assets, i.e., "docs/home.html".
-     * 
+     *
      * @return String[] Array of strings, one for each asset.  These file
      *         names are relative to 'path'.  You can open the file by
      *         concatenating 'path' and a name in the returned string (via
      *         File) and passing that to open().
-     * 
+     *
      * @see #open
      */
     public @Nullable String[] list(@NonNull String path) throws IOException {
@@ -1167,20 +1167,20 @@
             return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
         }
     }
-    
+
     /**
      * Retrieve a parser for a compiled XML file.
-     * 
+     *
      * @param fileName The name of the file to retrieve.
      */
     public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
             throws IOException {
         return openXmlResourceParser(0, fileName);
     }
-    
+
     /**
      * Retrieve a parser for a compiled XML file.
-     * 
+     *
      * @param cookie Identifier of the package to be opened.
      * @param fileName The name of the file to retrieve.
      */
@@ -1200,7 +1200,7 @@
 
     /**
      * Retrieve a non-asset as a compiled XML file.  Not for use by applications.
-     * 
+     *
      * @param fileName The name of the file to retrieve.
      * @hide
      */
@@ -1211,7 +1211,7 @@
     /**
      * Retrieve a non-asset as a compiled XML file.  Not for use by
      * applications.
-     * 
+     *
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
      * @hide
@@ -1675,7 +1675,6 @@
                 mRefStacks = new HashMap<>();
             }
             RuntimeException ex = new RuntimeException();
-            ex.fillInStackTrace();
             mRefStacks.put(id, ex);
         }
         mNumRefs++;
diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java
index b162ad6..6343ba1 100644
--- a/core/java/android/hardware/DisplayLuts.java
+++ b/core/java/android/hardware/DisplayLuts.java
@@ -16,116 +16,294 @@
 
 package android.hardware;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.hardware.flags.Flags;
 import android.util.IntArray;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
- * @hide
+ * DisplayLuts provides the developers to apply Lookup Tables (Luts) to a
+ * {@link android.view.SurfaceControl}. Luts provides ways to control tonemapping
+ * for specific content.
+ *
+ * The general flow is as follows:
+ * <p>
+ *      <img src="{@docRoot}reference/android/images/graphics/DisplayLuts.png" />
+ *      <figcaption style="text-align: center;">DisplayLuts flow</figcaption>
+ * </p>
+ *
+ * @see LutProperties
  */
+@FlaggedApi(Flags.FLAG_LUTS_API)
 public final class DisplayLuts {
+    private ArrayList<Entry> mEntries;
     private IntArray mOffsets;
     private int mTotalLength;
 
-    private List<float[]> mLutBuffers;
-    private IntArray mLutDimensions;
-    private IntArray mLutSizes;
-    private IntArray mLutSamplingKeys;
-    private static final int LUT_LENGTH_LIMIT = 100000;
-
+    /**
+     * Create a {@link DisplayLuts} instance.
+     */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public DisplayLuts() {
+        mEntries = new ArrayList<>();
         mOffsets = new IntArray();
         mTotalLength = 0;
-
-        mLutBuffers = new ArrayList<>();
-        mLutDimensions = new IntArray();
-        mLutSizes = new IntArray();
-        mLutSamplingKeys = new IntArray();
     }
 
-    /**
-     * Add the lut to be applied.
-     *
-     * @param buffer
-     * @param dimension either 1D or 3D
-     * @param size
-     * @param samplingKey
-     */
-    public void addLut(@NonNull float[] buffer, @LutProperties.Dimension int dimension,
-                       int size, @LutProperties.SamplingKey int samplingKey) {
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    public static class Entry {
+        private float[] mBuffer;
+        private @LutProperties.Dimension int mDimension;
+        private int mSize;
+        private @LutProperties.SamplingKey int mSamplingKey;
 
-        int lutLength = 0;
-        if (dimension == LutProperties.ONE_DIMENSION) {
-            lutLength = size;
-        } else if (dimension == LutProperties.THREE_DIMENSION) {
-            lutLength = size * size * size;
-        } else {
-            clear();
-            throw new IllegalArgumentException("The dimension is either 1D or 3D!");
+        private static final int LUT_LENGTH_LIMIT = 100000;
+
+        /**
+         * Create a Lut entry.
+         *
+         * <p>
+         * Noted that 1D Lut(s) are treated as gain curves.
+         * For 3D Lut(s), 3D Lut(s) are used for direct color manipulations.
+         * The values of 3D Lut(s) data should be normalized to the range {@code 0.0}
+         * to {@code 1.0}, inclusive. And 3D Lut(s) data is organized in the order of
+         * R, G, B channels.
+         *
+         * @param buffer The raw lut data
+         * @param dimension Either 1D or 3D
+         * @param samplingKey The sampling kay used for the Lut
+         */
+        @FlaggedApi(Flags.FLAG_LUTS_API)
+        public Entry(@NonNull float[] buffer,
+                    @LutProperties.Dimension int dimension,
+                    @LutProperties.SamplingKey int samplingKey) {
+            if (buffer == null || buffer.length < 1) {
+                throw new IllegalArgumentException("The buffer cannot be empty!");
+            }
+
+            if (buffer.length >= LUT_LENGTH_LIMIT) {
+                throw new IllegalArgumentException("The lut length is too big to handle!");
+            }
+
+            if (dimension != LutProperties.ONE_DIMENSION
+                    && dimension != LutProperties.THREE_DIMENSION) {
+                throw new IllegalArgumentException("The dimension should be either 1D or 3D!");
+            }
+
+            if (dimension == LutProperties.THREE_DIMENSION) {
+                if (buffer.length <= 3) {
+                    throw new IllegalArgumentException(
+                            "The 3d lut size of each dimension should be over 1!");
+                }
+                int lengthPerChannel = buffer.length;
+                if (lengthPerChannel % 3 != 0) {
+                    throw new IllegalArgumentException(
+                            "The lut buffer of 3dlut should have 3 channels!");
+                }
+                lengthPerChannel /= 3;
+
+                double size = Math.cbrt(lengthPerChannel);
+                if (size == (int) size) {
+                    mSize = (int) size;
+                } else {
+                    throw new IllegalArgumentException(
+                            "Cannot get the cube root of the 3d lut buffer!");
+                }
+            } else {
+                mSize = buffer.length;
+            }
+
+            mBuffer = buffer;
+            mDimension = dimension;
+            mSamplingKey = samplingKey;
         }
 
-        if (lutLength >= LUT_LENGTH_LIMIT) {
-            clear();
-            throw new IllegalArgumentException("The lut length is too big to handle!");
+        /**
+         * @return the dimension of the lut entry
+         */
+        @FlaggedApi(Flags.FLAG_LUTS_API)
+        public int getDimension() {
+            return mDimension;
         }
 
+        /**
+         * @return the size of the lut for each dimension
+         * @hide
+         */
+        public int getSize() {
+            return mSize;
+        }
+
+        /**
+         * @return the lut raw data of the lut
+         */
+        @FlaggedApi(Flags.FLAG_LUTS_API)
+        public @NonNull float[] getBuffer() {
+            return mBuffer;
+        }
+
+        /**
+         * @return the sampling key used by the lut
+         */
+        @FlaggedApi(Flags.FLAG_LUTS_API)
+        public int getSamplingKey() {
+            return mSamplingKey;
+        }
+
+        @Override
+        public String toString() {
+            return "Entry{"
+                    + "dimension=" + DisplayLuts.Entry.dimensionToString(getDimension())
+                    + ", size(each dimension)=" + getSize()
+                    + ", samplingKey=" + samplingKeyToString(getSamplingKey()) + "}";
+        }
+
+        private static String dimensionToString(int dimension) {
+            switch(dimension) {
+                case LutProperties.ONE_DIMENSION:
+                    return "ONE_DIMENSION";
+                case LutProperties.THREE_DIMENSION:
+                    return "THREE_DIMENSION";
+                default:
+                    return "";
+            }
+        }
+
+        private static String samplingKeyToString(int key) {
+            switch(key) {
+                case LutProperties.SAMPLING_KEY_RGB:
+                    return "SAMPLING_KEY_RGB";
+                case LutProperties.SAMPLING_KEY_MAX_RGB:
+                    return "SAMPLING_KEY_MAX_RGB";
+                default:
+                    return "";
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("DisplayLuts{");
+        sb.append("\n");
+        for (DisplayLuts.Entry entry: mEntries) {
+            sb.append(entry.toString());
+            sb.append("\n");
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    private void addEntry(Entry entry) {
+        mEntries.add(entry);
         mOffsets.add(mTotalLength);
-        mTotalLength += lutLength;
-
-        mLutBuffers.add(buffer);
-        mLutDimensions.add(dimension);
-        mLutSizes.add(size);
-        mLutSamplingKeys.add(samplingKey);
+        mTotalLength += entry.getBuffer().length;
     }
 
     private void clear() {
-        mTotalLength = 0;
         mOffsets.clear();
-        mLutBuffers.clear();
-        mLutDimensions.clear();
-        mLutSamplingKeys.clear();
+        mTotalLength = 0;
+        mEntries.clear();
     }
 
     /**
-     * @return the array of Lut buffers
+     * Set a Lut to be applied.
+     *
+     * <p>Use either this or {@link #set(Entry, Entry)}. The function will
+     * replace any previously set lut(s).</p>
+     *
+     * @param entry Either an 1D Lut or a 3D Lut
+     */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    public void set(@NonNull Entry entry) {
+        if (entry == null) {
+            throw new IllegalArgumentException("The entry is null!");
+        }
+        clear();
+        addEntry(entry);
+    }
+
+    /**
+     * Set Luts in order to be applied.
+     *
+     * <p> An 1D Lut and 3D Lut will be applied in order. Use either this or
+     * {@link #set(Entry)}. The function will replace any previously set lut(s)</p>
+     *
+     * @param first An 1D Lut
+     * @param second A 3D Lut
+     */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    public void set(@NonNull Entry first, @NonNull Entry second) {
+        if (first == null || second == null) {
+            throw new IllegalArgumentException("The entry is null!");
+        }
+        if (first.getDimension() != LutProperties.ONE_DIMENSION
+                || second.getDimension() != LutProperties.THREE_DIMENSION) {
+            throw new IllegalArgumentException("The entries should be 1D and 3D in order!");
+        }
+        clear();
+        addEntry(first);
+        addEntry(second);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean valid() {
+        return mEntries.size() > 0;
+    }
+
+    /**
+     * @hide
      */
     public float[] getLutBuffers() {
         float[] buffer = new float[mTotalLength];
 
-        for (int i = 0; i < mLutBuffers.size(); i++) {
-            float[] lutBuffer = mLutBuffers.get(i);
+        for (int i = 0; i < mEntries.size(); i++) {
+            float[] lutBuffer = mEntries.get(i).getBuffer();
             System.arraycopy(lutBuffer, 0, buffer, mOffsets.get(i), lutBuffer.length);
         }
         return buffer;
     }
 
     /**
-     * @return the starting point of each lut memory region of the lut buffer
+     * @hide
      */
     public int[] getOffsets() {
         return mOffsets.toArray();
     }
 
     /**
-     * @return the array of Lut size
+     * @hide
      */
     public int[] getLutSizes() {
-        return mLutSizes.toArray();
+        int[] sizes = new int[mEntries.size()];
+        for (int i = 0; i < mEntries.size(); i++) {
+            sizes[i] = mEntries.get(i).getSize();
+        }
+        return sizes;
     }
 
     /**
-     * @return the array of Lut dimension
+     * @hide
      */
     public int[] getLutDimensions() {
-        return mLutDimensions.toArray();
+        int[] dimensions = new int[mEntries.size()];
+        for (int i = 0; i < mEntries.size(); i++) {
+            dimensions[i] = mEntries.get(i).getDimension();
+        }
+        return dimensions;
     }
 
     /**
-     * @return the array of sampling key
+     * @hide
      */
     public int[] getLutSamplingKeys() {
-        return mLutSamplingKeys.toArray();
+        int[] samplingKeys = new int[mEntries.size()];
+        for (int i = 0; i < mEntries.size(); i++) {
+            samplingKeys[i] = mEntries.get(i).getSamplingKey();
+        }
+        return samplingKeys;
     }
 }
diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java
index c9c6d6d..bf40a41 100644
--- a/core/java/android/hardware/LutProperties.java
+++ b/core/java/android/hardware/LutProperties.java
@@ -16,23 +16,31 @@
 
 package android.hardware;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Lut properties class.
+ * Provides Lut properties of the device.
  *
- * A Lut (Look-Up Table) is a pre-calculated table for color transformation.
- *
- * @hide
+ * <p>
+ * A Lut (Look-Up Table) is a pre-calculated table for color correction.
+ * Applications may be interested in the Lut properties exposed by
+ * this class to determine if the Lut(s) they select using
+ * {@link android.view.SurfaceControl.Transaction#setLuts} are by the HWC.
+ * </p>
  */
+@FlaggedApi(Flags.FLAG_LUTS_API)
 public final class LutProperties {
     private final @Dimension int mDimension;
     private final int mSize;
     private final @SamplingKey int[] mSamplingKeys;
 
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SAMPLING_KEY_"}, value = {
         SAMPLING_KEY_RGB,
@@ -42,11 +50,14 @@
     }
 
     /** use r,g,b channel as the gain value of a Lut */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public static final int SAMPLING_KEY_RGB = 0;
 
     /** use max of r,g,b channel as the gain value of a Lut */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public static final int SAMPLING_KEY_MAX_RGB = 1;
 
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
         ONE_DIMENSION,
@@ -56,18 +67,22 @@
     }
 
     /** The Lut is one dimensional */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public static final int ONE_DIMENSION = 1;
 
     /** The Lut is three dimensional */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public static final int THREE_DIMENSION = 3;
 
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public @Dimension int getDimension() {
         return mDimension;
     }
 
     /**
-     * @return the size of the Lut.
+     * @return the size of the Lut for each dimension
      */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
     public int getSize() {
         return mSize;
     }
@@ -75,6 +90,8 @@
     /**
      * @return the list of sampling keys
      */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    @NonNull
     public @SamplingKey int[] getSamplingKeys() {
         if (mSamplingKeys.length == 0) {
             throw new IllegalStateException("no sampling key!");
diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java
index 24cfc1b..d42bfae 100644
--- a/core/java/android/hardware/OverlayProperties.java
+++ b/core/java/android/hardware/OverlayProperties.java
@@ -18,6 +18,7 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.SuppressLint;
 import android.hardware.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -72,9 +73,11 @@
     }
 
     /**
-     * Gets the lut properties of the display.
-     * @hide
+     * Returns the lut properties of the device.
      */
+    @FlaggedApi(Flags.FLAG_LUTS_API)
+    @SuppressLint("ArrayReturn")
+    @NonNull
     public LutProperties[] getLutProperties() {
         if (mNativeObject == 0) {
             return null;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 58e524e..5533a64 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -19,9 +19,9 @@
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.ExtensionKey;
 import android.hardware.camera2.impl.PublicKey;
 import android.hardware.camera2.impl.SyntheticKey;
 import android.hardware.camera2.params.DeviceStateSensorOrientationMap;
@@ -6172,6 +6172,66 @@
     public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION =
             new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.jpegr.availableJpegRStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class);
 
+    /**
+     * <p>Color space used for shared session configuration for all the output targets
+     * when camera is opened in shared mode. This should be one of the values specified in
+     * availableColorSpaceProfilesMap.</p>
+     * <p><b>Possible values:</b></p>
+     * <ul>
+     *   <li>{@link #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED UNSPECIFIED}</li>
+     *   <li>{@link #SHARED_SESSION_COLOR_SPACE_SRGB SRGB}</li>
+     *   <li>{@link #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 DISPLAY_P3}</li>
+     *   <li>{@link #SHARED_SESSION_COLOR_SPACE_BT2020_HLG BT2020_HLG}</li>
+     * </ul>
+     *
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @see #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED
+     * @see #SHARED_SESSION_COLOR_SPACE_SRGB
+     * @see #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3
+     * @see #SHARED_SESSION_COLOR_SPACE_BT2020_HLG
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final Key<Integer> SHARED_SESSION_COLOR_SPACE =
+            new Key<Integer>("android.sharedSession.colorSpace", int.class);
+
+    /**
+     * <p>List of shared output configurations that this camera device supports when
+     * camera is opened in shared mode. Array contains following entries for each supported
+     * shared configuration:
+     * 1) surface type
+     * 2) width
+     * 3) height
+     * 4) format
+     * 5) mirrorMode
+     * 6) useReadoutTimestamp
+     * 7) timestampBase
+     * 8) dataspace
+     * 9) usage
+     * 10) streamUsecase
+     * 11) physical camera id len
+     * 12) physical camera id as UTF-8 null terminated string.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final Key<long[]> SHARED_SESSION_OUTPUT_CONFIGURATIONS =
+            new Key<long[]>("android.sharedSession.outputConfigurations", long[].class);
+
+    /**
+     * <p>The available stream configurations that this camera device supports for
+     * shared capture session when camera is opened in shared mode. Android camera framework
+     * will generate this tag if the camera device can be opened in shared mode.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    @SyntheticKey
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION =
+            new Key<android.hardware.camera2.params.SharedSessionConfiguration>("android.sharedSession.configuration", android.hardware.camera2.params.SharedSessionConfiguration.class);
+
 
     /**
      * Mapping from INFO_SESSION_CONFIGURATION_QUERY_VERSION to session characteristics key.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fb381d9..852f047 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -446,6 +446,17 @@
     public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED =
             1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE;
 
+     /**
+     * Shared camera operation mode.
+     *
+     * @see #CameraSharedCaptureSession
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final int SESSION_OPERATION_MODE_SHARED =
+            2; // ICameraDeviceUser.SHARED_MODE;
+
     /**
      * First vendor-specific operating mode
      *
@@ -461,6 +472,7 @@
     @IntDef(prefix = {"SESSION_OPERATION_MODE"}, value =
             {SESSION_OPERATION_MODE_NORMAL,
              SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED,
+             SESSION_OPERATION_MODE_SHARED,
              SESSION_OPERATION_MODE_VENDOR_START})
     public @interface SessionOperatingMode {};
 
@@ -1240,7 +1252,6 @@
      *
      * </ul>
      *
-     *
      * @param config A session configuration (see {@link SessionConfiguration}).
      *
      * @throws IllegalArgumentException In case the session configuration is invalid; or the output
@@ -1559,6 +1570,48 @@
         public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
 
         /**
+         * The method called when a camera device has finished opening in shared mode,
+         * where there can be more than one client accessing the same camera.
+         *
+         * <p>At this point, the camera device is ready to use, and
+         * {@link CameraDevice#createCaptureSession} can be called to set up the shared capture
+         * session.</p>
+         *
+         * @param camera the camera device that has become opened
+         * @param isPrimaryClient true if the client opening the camera is currently the primary
+         *                             client.
+         * @hide
+         */
+        @SystemApi
+        @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+        public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean isPrimaryClient) {
+          // Default empty implementation
+        }
+
+        /**
+         * The method called when client access priorities have changed for a camera device opened
+         * in shared mode where there can be more than one client accessing the same camera.
+         *
+         * If the client priority changed from secondary to primary, then it can now
+         * create capture request and change the capture request parameters. If client priority
+         * changed from primary to secondary, that implies that a higher priority client has also
+         * opened the camera in shared mode and the new client is now a primary client
+         *
+         * @param camera the camera device whose access priorities have changed.
+         * @param isPrimaryClient true if the client is now the primary client.
+         *                        false if another higher priority client also opened the
+         *                        camera and is now the new primary client and this client is
+         *                        now a secondary client.
+         * @hide
+         */
+        @SystemApi
+        @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+        public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera,
+                boolean isPrimaryClient) {
+          // Default empty implementation
+        }
+
+        /**
          * The method called when a camera device has been closed with
          * {@link CameraDevice#close}.
          *
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 75e2058..266efb7 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -976,6 +976,46 @@
     }
 
     /**
+     * Checks if a camera device can be opened in a shared mode for a given {@code cameraId}.
+     * If this method returns false for a {@code cameraId}, calling {@link #openSharedCamera}
+     * for that {@code cameraId} will throw an {@link UnsupportedOperationException}.
+     *
+     * @param cameraId The unique identifier of the camera device for which sharing support is
+     *                 being queried. This identifier must be present in
+     *                 {@link #getCameraIdList()}.
+     *
+     * @return {@code true} if camera can be opened in shared mode
+     *                      for the provided {@code cameraId}; {@code false} otherwise.
+     *
+     * @throws IllegalArgumentException If {@code cameraId} is null, or if {@code cameraId} does not
+     *                                  match any device in {@link #getCameraIdList()}.
+     * @throws CameraAccessException    if the camera device has been disconnected.
+     *
+     * @see #getCameraIdList()
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    @SystemApi
+    public boolean isCameraDeviceSharingSupported(@NonNull String cameraId)
+            throws CameraAccessException {
+        if (cameraId == null) {
+            throw new IllegalArgumentException("Camera ID was null");
+        }
+
+        if (CameraManagerGlobal.sCameraServiceDisabled
+                || !Arrays.asList(CameraManagerGlobal.get().getCameraIdList(mContext.getDeviceId(),
+                getDevicePolicyFromContext(mContext))).contains(cameraId)) {
+            throw new IllegalArgumentException(
+                    "Camera ID '" + cameraId + "' not available on device.");
+        }
+
+        CameraCharacteristics chars = getCameraCharacteristics(cameraId);
+        long[] sharedOutputConfiguration =
+                chars.get(CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS);
+        return (sharedOutputConfiguration != null);
+    }
+
+    /**
      * Retrieves the AttributionSourceState to pass to the CameraService.
      *
      * @param deviceIdOverride An override of the AttributionSource's deviceId, if not equal to
@@ -1036,6 +1076,9 @@
      * @param cameraId The unique identifier of the camera device to open
      * @param callback The callback for the camera. Must not be null.
      * @param executor The executor to invoke the callback with. Must not be null.
+     * @param oomScoreOffset The minimum oom score that cameraservice must see for this client.
+     * @param rotationOverride The type of rotation override.
+     * @param sharedMode Parameter specifying if the camera should be opened in shared mode.
      *
      * @throws CameraAccessException if the camera is disabled by device policy,
      * too many camera devices are already open, or the cameraId does not match
@@ -1051,7 +1094,8 @@
      */
     private CameraDevice openCameraDeviceUserAsync(String cameraId,
             CameraDevice.StateCallback callback, Executor executor,
-            final int oomScoreOffset, int rotationOverride) throws CameraAccessException {
+            final int oomScoreOffset, int rotationOverride, boolean sharedMode)
+            throws CameraAccessException {
         CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
         CameraDevice device = null;
         synchronized (mLock) {
@@ -1070,7 +1114,7 @@
                         characteristics,
                         this,
                         mContext.getApplicationInfo().targetSdkVersion,
-                        mContext, cameraDeviceSetup);
+                        mContext, cameraDeviceSetup, sharedMode);
             ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
 
             try {
@@ -1091,7 +1135,7 @@
                                 mContext.getApplicationInfo().targetSdkVersion,
                                 rotationOverride,
                                 clientAttribution,
-                                getDevicePolicyFromContext(mContext));
+                                getDevicePolicyFromContext(mContext), sharedMode);
             } catch (ServiceSpecificException e) {
                 if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
                     throw new AssertionError("Should've gone down the shim path");
@@ -1218,7 +1262,8 @@
             @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
             throws CameraAccessException {
 
-        openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler));
+        openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
+                /*oomScoreOffset*/0, getRotationOverride(mContext), /*sharedMode*/false);
     }
 
     /**
@@ -1258,7 +1303,7 @@
                          /*oomScoreOffset*/0,
                          overrideToPortrait
                                  ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
-                                 : ICameraService.ROTATION_OVERRIDE_NONE);
+                                 : ICameraService.ROTATION_OVERRIDE_NONE, /*sharedMode*/false);
     }
 
     /**
@@ -1303,10 +1348,57 @@
         if (executor == null) {
             throw new IllegalArgumentException("executor was null");
         }
-        openCameraImpl(cameraId, callback, executor);
+        openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
+                getRotationOverride(mContext), /*sharedMode*/false);
     }
 
     /**
+     * Opens a shared connection to a camera with the given ID.
+     *
+     * <p>The behavior of this method matches that of
+     * {@link #openCamera(String, Executor, StateCallback)}, except that it opens the camera in
+     * shared mode where more than one client can access the camera at the same time.</p>
+     *
+     * @param cameraId The unique identifier of the camera device to open.
+     * @param executor The executor which will be used when invoking the callback.
+     * @param callback The callback which is invoked once the camera is opened
+     *
+     * @throws CameraAccessException if the camera is disabled by device policy, or is being used
+     *                               by a higher-priority client in non-shared mode or the device
+     *                               has reached its maximal resource and cannot open this camera
+     *                               device.
+     *
+     * @throws IllegalArgumentException if cameraId, the callback or the executor was null,
+     *                                  or the cameraId does not match any currently or previously
+     *                                  available camera device.
+     *
+     * @throws SecurityException if the application does not have permission to
+     *                           access the camera
+     *
+     * @see #getCameraIdList
+     * @see android.app.admin.DevicePolicyManager#setCameraDisabled
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.SYSTEM_CAMERA,
+            android.Manifest.permission.CAMERA,
+    })
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public void openSharedCamera(@NonNull String cameraId,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull final CameraDevice.StateCallback callback)
+            throws CameraAccessException {
+        if (executor == null) {
+            throw new IllegalArgumentException("executor was null");
+        }
+        openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
+                getRotationOverride(mContext), /*sharedMode*/true);
+    }
+
+
+    /**
      * Open a connection to a camera with the given ID. Also specify what oom score must be offset
      * by cameraserver for this client. This api can be useful for system
      * components which want to assume a lower priority (for camera arbitration) than other clients
@@ -1372,29 +1464,35 @@
                     "oomScoreOffset < 0, cannot increase priority of camera client");
         }
         openCameraImpl(cameraId, callback, executor, oomScoreOffset,
-                getRotationOverride(mContext));
+                getRotationOverride(mContext), /*sharedMode*/false);
     }
 
     /**
      * Open a connection to a camera with the given ID, on behalf of another application.
-     * Also specify the minimum oom score and process state the application
-     * should have, as seen by the cameraserver.
      *
-     * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows
-     * the caller to specify the UID to use for permission/etc verification. This can only be
-     * done by services trusted by the camera subsystem to act on behalf of applications and
-     * to forward the real UID.</p>
-     *
+     * @param cameraId
+     *             The unique identifier of the camera device to open
+     * @param callback
+     *             The callback which is invoked once the camera is opened
+     * @param executor
+     *             The executor which will be used when invoking the callback.
      * @param oomScoreOffset
      *             The minimum oom score that cameraservice must see for this client.
      * @param rotationOverride
      *             The type of rotation override (none, override_to_portrait, rotation_only)
      *             that should be followed for this camera id connection
+     * @param sharedMode
+     *             Parameter specifying if the camera should be opened in shared mode.
+     *
+     * @throws CameraAccessException if the camera is disabled by device policy,
+     * has been disconnected, or is being used by a higher-priority camera API client in
+     * non shared mode.
+     *
      * @hide
      */
     public void openCameraImpl(@NonNull String cameraId,
             @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
-            int oomScoreOffset, int rotationOverride)
+            int oomScoreOffset, int rotationOverride, boolean sharedMode)
             throws CameraAccessException {
 
         if (cameraId == null) {
@@ -1407,24 +1505,7 @@
         }
 
         openCameraDeviceUserAsync(cameraId, callback, executor, oomScoreOffset,
-                rotationOverride);
-    }
-
-    /**
-     * Open a connection to a camera with the given ID, on behalf of another application.
-     *
-     * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows
-     * the caller to specify the UID to use for permission/etc verification. This can only be
-     * done by services trusted by the camera subsystem to act on behalf of applications and
-     * to forward the real UID.</p>
-     *
-     * @hide
-     */
-    public void openCameraImpl(@NonNull String cameraId,
-            @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor)
-            throws CameraAccessException {
-        openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0,
-                getRotationOverride(mContext));
+                rotationOverride, sharedMode);
     }
 
     /**
@@ -2541,6 +2622,10 @@
                 }
                 @Override
                 public void onCameraClosed(String id, int deviceId) {
+                }
+                @Override
+                public void onCameraOpenedInSharedMode(String id, String clientPackageId,
+                        int deviceId, boolean primaryClient) {
                 }};
 
             String[] cameraIds;
@@ -3325,6 +3410,11 @@
         }
 
         @Override
+        public void onCameraOpenedInSharedMode(String cameraId, String clientPackageId,
+                int deviceId, boolean primaryClient) {
+        }
+
+        @Override
         public void onCameraOpened(String cameraId, String clientPackageId, int deviceId) {
             synchronized (mLock) {
                 onCameraOpenedLocked(new DeviceCameraInfo(cameraId, deviceId), clientPackageId);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 8d36fbd..d2fcfd6 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2121,6 +2121,38 @@
     public static final int AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10;
 
     //
+    // Enumeration values for CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+    //
+
+    /**
+     * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final int SHARED_SESSION_COLOR_SPACE_UNSPECIFIED = -1;
+
+    /**
+     * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final int SHARED_SESSION_COLOR_SPACE_SRGB = 0;
+
+    /**
+     * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final int SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 = 7;
+
+    /**
+     * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public static final int SHARED_SESSION_COLOR_SPACE_BT2020_HLG = 16;
+
+    //
     // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE
     //
 
diff --git a/core/java/android/hardware/camera2/CameraSharedCaptureSession.java b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java
new file mode 100644
index 0000000..5426d4d
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.view.Surface;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A shared capture session for a {@link CameraDevice}, when a camera device is opened in shared
+ * mode possibly by multiple clients at the same time.
+ *
+ * <p>An active shared capture session is a special type of capture session used exclusively
+ * for shared camera access by multiple applications, provided the camera device supports this
+ * mode. To determine if a camera device supports shared mode, use the
+ * {@link android.hardware.camera2.CameraManager#isCameraDeviceSharingSupported} API.
+ * If supported, multiple clients can open the camera by calling
+ * {@link android.hardware.camera2.CameraManager#openSharedCamera} and create a shared capture
+ * session by calling {@link CameraDevice#createCaptureSession(SessionConfiguration)} and using
+ * session type as {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}</p>
+ *
+ * <p>When an application has opened a camera device in shared mode, it can only create a shared
+ * capture session using session type as
+ * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}. Any other session
+ * type value will trigger {@link IllegalArgumentException}. Once the configuration is complete and
+ * the session is ready to actually capture data, the provided
+ * {@link CameraCaptureSession.StateCallback}'s
+ * {@link CameraCaptureSession.StateCallback#onConfigured} callback will be called and will
+ * receive a CameraCaptureSession (castable to {@link CameraSharedCaptureSession}).</p>
+ *
+ * <p>Shared capture sessions uses a predefined configuration detailed in
+ * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION}. Using different configuration values
+ * when creating session will result in an {@link IllegalArgumentException}.</p>
+ *
+ * <p>When camera is opened in shared mode, the highest priority client among all the clients will
+ * be the primary client while the others would be secondary clients. Clients will know if they are
+ * primary or secondary by the device state callback
+ * {@link CameraDevice.StateCallback#onOpenedInSharedMode}. Once the camera has been opened in
+ * shared mode, their access priorities of being a primary or secondary client can change if
+ * another higher priority client opens the camera later. Once the camera has been opened,
+ * any change in primary client status will be shared by the device state callback
+ * {@link CameraDevice.StateCallback#onClientSharedAccessPriorityChanged}.</p>
+ *
+ * <p>The priority of client access is determined by considering two factors: its current process
+ * state and its "out of memory" score. Clients operating in the background are assigned a lower
+ * priority. In contrast, clients running in the foreground, along with system-level clients, are
+ * given a higher priority.</p>
+ *
+ * <p>Primary clients can create capture requests, modify any capture parameters and send them to
+ * the capture session for a one-shot capture or as a repeating request using the following apis:
+ * </p>
+ *
+ * <ul>
+ *
+ * <li>{@link CameraSharedCaptureSession#capture}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureSingleRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setSingleRepeatingRequest}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#stopRepeating}</li>
+ *
+ * </ul>
+ *
+ * <p>Secondary clients cannot create a capture request and modify any capture parameters. However,
+ * they can start the camera streaming to desired surface targets using
+ * {@link CameraSharedCaptureSession#startStreaming}, which will apply default parameters. Once the
+ * streaming has successfully started, then they can stop the streaming using
+ * {@link CameraSharedCaptureSession#stopStreaming}.</p>
+ *
+ * <p>The following APIs are not supported in shared capture sessions by either the primary or
+ * secondary client.</p>
+ *
+ * <ul>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureBurst}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#captureBurstRequests}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingBurst}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#setRepeatingBurstRequests}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#switchToOffline}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#updateOutputConfiguration}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#finalizeOutputConfigurations}</li>
+ *
+ * <li>{@link CameraSharedCaptureSession#prepare}</li>
+ *
+ * </ul>
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+@SystemApi
+public abstract class CameraSharedCaptureSession extends CameraCaptureSession {
+
+    /**
+     * Request start of the streaming of camera images by this shared capture session.
+     *
+     * <p>With this method, the camera device will continually capture images
+     * using the settings provided by primary client if there is ongoing repeating request
+     * by the primary client or default settings if no ongoing streaming request in progress.</p>
+     *
+     * <p> startStreaming has lower priority than the capture requests submitted
+     * through {@link #capture} by primary client, so if {@link #capture} is called when a
+     * streaming is active, the capture request will be processed before any further
+     * streaming requests are processed.</p>
+     *
+     * <p>To stop the streaming, call {@link #stopStreaming}</p>
+     *
+     * <p>Calling this method will replace any earlier streaming set up by this method.</p>
+     *
+     * @param surfaces List of target surfaces to use for streaming.
+     * @param executor The executor which will be used for invoking the listener.
+     * @param listener The callback object to notify the status and progress of the image capture.
+     *
+     * @return int A unique capture sequence ID used by
+     *             {@link CaptureCallback#onCaptureSequenceCompleted}.
+     *
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if this session is no longer active, either because the session
+     *                               was explicitly closed, a new session has been created
+     *                               or the camera device has been closed.
+     * @throws IllegalArgumentException If the request references no surfaces or references surfaces
+     *                                  that are not currently configured as outputs; or
+     *                                  the executor is null, or the listener is null.
+     * @see #stopStreaming
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    @SystemApi
+    public abstract int startStreaming(@NonNull List<Surface> surfaces,
+            @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener)
+            throws CameraAccessException;
+
+    /**
+     * <p>Cancel any ongoing streaming started by {@link #startStreaming}</p>
+     *
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if this session is no longer active, either because the session
+     *                               was explicitly closed, a new session has been created
+     *                               or the camera device has been closed.
+     *
+     * @see #startStreaming
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    @SystemApi
+    public abstract void stopStreaming() throws CameraAccessException;
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 8407258..ea70abb 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.compat.CompatChanges;
@@ -41,12 +42,15 @@
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.ICameraOfflineSession;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.DynamicRangeProfiles;
 import android.hardware.camera2.params.ExtensionSessionConfiguration;
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
 import android.hardware.camera2.params.MultiResolutionStreamInfo;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.SharedSessionConfiguration;
+import android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SurfaceUtils;
@@ -188,6 +192,8 @@
 
     private ExecutorService mOfflineSwitchService;
     private CameraOfflineSessionImpl mOfflineSessionImpl;
+    private boolean mSharedMode;
+    private boolean mIsPrimaryClient;
 
     // Runnables for all state transitions, except error, which needs the
     // error code argument
@@ -208,6 +214,25 @@
         }
     };
 
+    private final Runnable mCallOnOpenedInSharedMode = new Runnable() {
+        @Override
+        public void run() {
+            if (!Flags.cameraMultiClient()) {
+                return;
+            }
+            StateCallbackKK sessionCallback = null;
+            synchronized (mInterfaceLock) {
+                if (mRemoteDevice == null) return; // Camera already closed
+
+                sessionCallback = mSessionStateCallback;
+            }
+            if (sessionCallback != null) {
+                sessionCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient);
+            }
+            mDeviceCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient);
+        }
+    };
+
     private final Runnable mCallOnUnconfigured = new Runnable() {
         @Override
         public void run() {
@@ -322,6 +347,32 @@
                 }
             });
         }
+
+        public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean primaryClient) {
+            if (!Flags.cameraMultiClient()) {
+                return;
+            }
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onOpenedInSharedMode(camera, primaryClient);
+                }
+            });
+        }
+
+        public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera,
+                boolean primaryClient) {
+            if (!Flags.cameraMultiClient()) {
+                return;
+            }
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onClientSharedAccessPriorityChanged(camera, primaryClient);
+                }
+            });
+        }
+
         @Override
         public void onOpened(@NonNull CameraDevice camera) {
             mClientExecutor.execute(new Runnable() {
@@ -358,7 +409,8 @@
                         @NonNull CameraManager manager,
                         int appTargetSdkVersion,
                         Context ctx,
-                        @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup) {
+                        @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup,
+                        boolean sharedMode) {
         if (cameraId == null || callback == null || executor == null || characteristics == null
                 || manager == null) {
             throw new IllegalArgumentException("Null argument given");
@@ -375,6 +427,7 @@
         mAppTargetSdkVersion = appTargetSdkVersion;
         mContext = ctx;
         mCameraDeviceSetup = cameraDeviceSetup;
+        mSharedMode = sharedMode;
 
         final int MAX_TAG_LEN = 23;
         String tag = String.format("CameraDevice-JV-%s", mCameraId);
@@ -438,7 +491,12 @@
                 }
             }
 
-            mDeviceExecutor.execute(mCallOnOpened);
+            if (Flags.cameraMultiClient() && mSharedMode) {
+                mIsPrimaryClient = mRemoteDevice.isPrimaryClient();
+                mDeviceExecutor.execute(mCallOnOpenedInSharedMode);
+            } else {
+                mDeviceExecutor.execute(mCallOnOpened);
+            }
             mDeviceExecutor.execute(mCallOnUnconfigured);
 
             mRemoteDeviceInit = true;
@@ -576,7 +634,11 @@
             stopRepeating();
 
             try {
-                waitUntilIdle();
+                // if device is opened in shared mode, there can be multiple clients accessing the
+                // camera device. So do not wait for idle if the device is opened in shared mode.
+                if (!mSharedMode) {
+                    waitUntilIdle();
+                }
 
                 mRemoteDevice.beginConfigure();
 
@@ -764,6 +826,54 @@
                 checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null);
     }
 
+    private boolean checkSharedOutputConfiguration(OutputConfiguration outConfig) {
+        if (!Flags.cameraMultiClient()) {
+            return false;
+        }
+        SharedSessionConfiguration sharedSessionConfiguration =
+                mCharacteristics.get(CameraCharacteristics.SHARED_SESSION_CONFIGURATION);
+        if (sharedSessionConfiguration == null) {
+            return false;
+        }
+
+        List<SharedOutputConfiguration> sharedConfigs =
+                sharedSessionConfiguration.getOutputStreamsInformation();
+        for (SharedOutputConfiguration sharedConfig : sharedConfigs) {
+            if (outConfig.getConfiguredSize().equals(sharedConfig.getSize())
+                    && (outConfig.getConfiguredFormat() == sharedConfig.getFormat())
+                    && (outConfig.getSurfaceGroupId() == OutputConfiguration.SURFACE_GROUP_ID_NONE)
+                    && (outConfig.getSurfaceType() == sharedConfig.getSurfaceType())
+                    && (outConfig.getMirrorMode() == sharedConfig.getMirrorMode())
+                    && (outConfig.getUsage() == sharedConfig.getUsage())
+                    && (outConfig.isReadoutTimestampEnabled()
+                    == sharedConfig.isReadoutTimestampEnabled())
+                    && (outConfig.getTimestampBase() == sharedConfig.getTimestampBase())
+                    && (outConfig.getStreamUseCase() == sharedConfig.getStreamUseCase())
+                    && (outConfig.getColorSpace().equals(
+                    sharedSessionConfiguration.getColorSpace()))
+                    && (outConfig.getDynamicRangeProfile()
+                    == DynamicRangeProfiles.STANDARD)
+                    && (outConfig.getConfiguredDataspace() == sharedConfig.getDataspace())
+                    && (Objects.equals(outConfig.getPhysicalCameraId(),
+                    sharedConfig.getPhysicalCameraId()))
+                    && (outConfig.getSensorPixelModes().isEmpty())
+                    && (!outConfig.isShared())) {
+                //Found valid config, return true
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean checkSharedSessionConfiguration(List<OutputConfiguration> outputConfigs) {
+        for (OutputConfiguration out : outputConfigs) {
+            if (!checkSharedOutputConfiguration(out)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public void createCaptureSession(SessionConfiguration config)
             throws CameraAccessException {
@@ -778,6 +888,14 @@
         if (config.getExecutor() == null) {
             throw new IllegalArgumentException("Invalid executor");
         }
+        if (mSharedMode) {
+            if (config.getSessionType() != SessionConfiguration.SESSION_SHARED) {
+                throw new IllegalArgumentException("Invalid session type");
+            }
+            if (!checkSharedSessionConfiguration(outputConfigs)) {
+                throw new IllegalArgumentException("Invalid output configurations");
+            }
+        }
         createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs,
                 config.getStateCallback(), config.getExecutor(), config.getSessionType(),
                 config.getSessionParameters());
@@ -801,6 +919,11 @@
                 throw new IllegalArgumentException("Constrained high speed session doesn't support"
                         + " input configuration yet.");
             }
+            boolean isSharedSession = (operatingMode == ICameraDeviceUser.SHARED_MODE);
+            if (isSharedSession && inputConfig != null) {
+                throw new IllegalArgumentException("Shared capture session doesn't support"
+                        + " input configuration yet.");
+            }
 
             if (mCurrentExtensionSession != null) {
                 mCurrentExtensionSession.commitStats();
@@ -860,6 +983,10 @@
                 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
                         callback, executor, this, mDeviceExecutor, configureSuccess,
                         mCharacteristics);
+            } else if (isSharedSession) {
+                newSession = new CameraSharedCaptureSessionImpl(mNextSessionId++,
+                        callback, executor, this, mDeviceExecutor, configureSuccess,
+                        mIsPrimaryClient);
             } else {
                 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
                         callback, executor, this, mDeviceExecutor, configureSuccess);
@@ -1882,6 +2009,40 @@
         }
     }
 
+    /**
+     * Callback when client access priorities change when camera is opened in shared mode.
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+        if (DEBUG) {
+            Log.d(TAG, String.format(
+                    "onClientSharedAccessPriorityChanged received, primary client = "
+                    + primaryClient));
+        }
+        synchronized (mInterfaceLock) {
+            if (mRemoteDevice == null && mRemoteDeviceInit) {
+                return; // Camera already closed, user is not interested in this callback anymore.
+            }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mDeviceExecutor.execute(obtainRunnable(
+                        CameraDeviceImpl::notifyClientSharedAccessPriorityChanged, this,
+                        primaryClient).recycleOnUse());
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    private void notifyClientSharedAccessPriorityChanged(boolean primaryClient) {
+        if (!CameraDeviceImpl.this.isClosed()) {
+            mIsPrimaryClient = primaryClient;
+            mDeviceCallback.onClientSharedAccessPriorityChanged(CameraDeviceImpl.this,
+                    primaryClient);
+        }
+    }
+
     public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
         if (DEBUG) {
             Log.d(TAG, String.format(
@@ -2447,6 +2608,12 @@
         }
 
         @Override
+        @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+        public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+            CameraDeviceImpl.this.onClientSharedAccessPriorityChanged(primaryClient);
+        }
+
+        @Override
         public void onPrepared(int streamId) {
             final OutputConfiguration output;
             final StateCallbackKK sessionCallback;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 1cc0856..c0a5928 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -63,6 +63,7 @@
 import android.hardware.camera2.params.RecommendedStreamConfiguration;
 import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
 import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.SharedSessionConfiguration;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
@@ -866,6 +867,15 @@
                         return (T) metadata.getLensIntrinsicSamples();
                     }
                 });
+        sGetCommandMap.put(
+                CameraCharacteristics.SHARED_SESSION_CONFIGURATION.getNativeKey(),
+                        new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getSharedSessionConfiguration();
+                    }
+                });
     }
 
     private int[] getAvailableFormats() {
@@ -1658,6 +1668,22 @@
                 listHighResolution);
     }
 
+    private SharedSessionConfiguration getSharedSessionConfiguration() {
+        if (!Flags.cameraMultiClient()) {
+            return null;
+        }
+        Integer sharedSessionColorSpace = getBase(
+                CameraCharacteristics.SHARED_SESSION_COLOR_SPACE);
+        long[] sharedOutputConfigurations = getBase(
+                CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS);
+
+        if ((sharedSessionColorSpace == null) || (sharedOutputConfigurations == null)) {
+            return null;
+        }
+
+        return new SharedSessionConfiguration(sharedSessionColorSpace, sharedOutputConfigurations);
+    }
+
     private StreamConfigurationMap getStreamConfigurationMapMaximumResolution() {
         StreamConfiguration[] configurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION);
diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
index eb2ff88..1769c46 100644
--- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
@@ -16,11 +16,13 @@
 
 package android.hardware.camera2.impl;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.FlaggedApi;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraOfflineSession;
 import android.hardware.camera2.CameraOfflineSession.CameraOfflineSessionCallback;
 import android.hardware.camera2.CaptureFailure;
@@ -40,15 +42,15 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import com.android.internal.camera.flags.Flags;
+
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.Executor;
-
-import static com.android.internal.util.Preconditions.*;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class CameraOfflineSessionImpl extends CameraOfflineSession
         implements IBinder.DeathRecipient {
@@ -176,6 +178,12 @@
         }
 
         @Override
+        @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+        public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+            Log.v(TAG, "onClientSharedAccessPriorityChanged primaryClient = " + primaryClient);
+        }
+
+        @Override
         public void onDeviceIdle() {
             synchronized(mInterfaceLock) {
                 if (mRemoteSession == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java
new file mode 100644
index 0000000..a1f31c0
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.impl;
+
+import android.annotation.FlaggedApi;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraSharedCaptureSession;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.view.Surface;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Standard implementation of CameraSharedCaptureSession.
+ *
+ * <p>
+ * Mostly just forwards calls to an instance of CameraCaptureSessionImpl,
+ * but implements the few necessary behavior changes and additional methods required
+ * for the shared session mode.
+ * </p>
+ */
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+public class CameraSharedCaptureSessionImpl
+        extends CameraSharedCaptureSession implements CameraCaptureSessionCore {
+    private static final String TAG = "CameraSharedCaptureSessionImpl";
+    private final CameraCaptureSessionImpl mSessionImpl;
+    private final ConditionVariable mInitialized = new ConditionVariable();
+    private boolean mIsPrimary;
+
+    /**
+     * Create a new CameraCaptureSession.
+     */
+    CameraSharedCaptureSessionImpl(int id,
+            CameraCaptureSession.StateCallback callback, Executor stateExecutor,
+            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
+            Executor deviceStateExecutor, boolean configureSuccess, boolean isPrimary) {
+        CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
+        mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
+                stateExecutor, deviceImpl, deviceStateExecutor, configureSuccess);
+        mIsPrimary = isPrimary;
+        mInitialized.open();
+    }
+
+    @Override
+    public int startStreaming(List<Surface> surfaces, Executor executor, CaptureCallback listener)
+            throws CameraAccessException {
+        // Todo: Need to add implementation.
+        return 0;
+    }
+
+    @Override
+    public void stopStreaming() throws CameraAccessException {
+      // Todo: Need to add implementation.
+    }
+
+    @Override
+    public void close() {
+        mSessionImpl.close();
+    }
+
+    @Override
+    public Surface getInputSurface() {
+        return null;
+    }
+
+    @Override
+    public boolean isReprocessable() {
+        return false;
+    }
+
+    @Override
+    public void abortCaptures() throws CameraAccessException {
+        if (mIsPrimary) {
+            mSessionImpl.abortCaptures();
+        }
+    }
+
+    @Override
+    public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener,
+            Handler handler) throws CameraAccessException {
+        if (mIsPrimary) {
+            return mSessionImpl.setRepeatingRequest(request, listener, handler);
+        }
+        throw new UnsupportedOperationException("Shared capture session only supports this method"
+                + " for primary clients");
+    }
+
+    @Override
+    public void stopRepeating() throws CameraAccessException {
+        if (mIsPrimary) {
+            mSessionImpl.stopRepeating();
+        }
+    }
+
+    @Override
+    public int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
+            throws CameraAccessException {
+        if (mIsPrimary) {
+            return mSessionImpl.capture(request, listener, handler);
+        }
+        throw new UnsupportedOperationException("Shared capture session only supports this method"
+                + " for primary clients");
+    }
+
+    @Override
+    public void tearDown(Surface surface) throws CameraAccessException {
+        mSessionImpl.tearDown(surface);
+    }
+
+    @Override
+    public CameraDevice getDevice() {
+        return mSessionImpl.getDevice();
+    }
+
+    @Override
+    public boolean isAborting() {
+        return mSessionImpl.isAborting();
+    }
+
+    @Override
+    public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
+        return mSessionImpl.getDeviceStateCallback();
+    }
+
+    @Override
+    public void replaceSessionClose() {
+        mSessionImpl.replaceSessionClose();
+    }
+
+    @Override
+    public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener,
+            Handler handler) throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared Capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener,
+            Handler handler) throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared Capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public void updateOutputConfiguration(OutputConfiguration config)
+            throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs)
+            throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public void prepare(Surface surface) throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public void prepare(int maxCount, Surface surface) throws CameraAccessException {
+        throw new UnsupportedOperationException("Shared capture session doesn't support"
+                + " this method");
+    }
+
+    @Override
+    public void closeWithoutDraining() {
+        throw new UnsupportedOperationException("Shared capture session doesn't support"
+                + " this method");
+    }
+
+    private class WrapperCallback extends StateCallback {
+        private final StateCallback mCallback;
+
+        WrapperCallback(StateCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onConfigured(CameraCaptureSession session) {
+            mInitialized.block();
+            mCallback.onConfigured(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onConfigureFailed(CameraCaptureSession session) {
+            mInitialized.block();
+            mCallback.onConfigureFailed(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onReady(CameraCaptureSession session) {
+            mCallback.onReady(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onActive(CameraCaptureSession session) {
+            mCallback.onActive(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onCaptureQueueEmpty(CameraCaptureSession session) {
+            mCallback.onCaptureQueueEmpty(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onClosed(CameraCaptureSession session) {
+            mCallback.onClosed(CameraSharedCaptureSessionImpl.this);
+        }
+
+        @Override
+        public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
+            mCallback.onSurfacePrepared(CameraSharedCaptureSessionImpl.this,
+                    surface);
+        }
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index aec2cff..831c75ec 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -301,4 +301,16 @@
         }
     }
 
+    /**
+     * API to check if the client is primary client when camera device is opened in shared mode.
+     */
+    public boolean isPrimaryClient() throws CameraAccessException {
+        try {
+            return mRemoteDevice.isPrimaryClient();
+        } catch (ServiceSpecificException e) {
+            throw ExceptionUtils.throwAsPublicException(e);
+        } catch (RemoteException e) {
+            throw ExceptionUtils.throwAsPublicException(e);
+        }
+    }
 }
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index d38be9b..e12c463 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -29,6 +29,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.ImageFormat;
 import android.graphics.ImageFormat.Format;
+import android.hardware.DataSpace.NamedDataSpace;
 import android.hardware.HardwareBuffer;
 import android.hardware.HardwareBuffer.Usage;
 import android.hardware.camera2.CameraCaptureSession;
@@ -1729,6 +1730,79 @@
     }
 
     /**
+     * Get the configured format associated with this {@link OutputConfiguration}.
+     *
+     * @return {@link android.graphics.ImageFormat#Format} associated with this
+     *         {@link OutputConfiguration}.
+     *
+     * @hide
+     */
+    public @Format int getConfiguredFormat() {
+        return mConfiguredFormat;
+    }
+
+    /**
+     * Get the usage flag associated with this {@link OutputConfiguration}.
+     *
+     * @return {@link HardwareBuffer#Usage} associated with this {@link OutputConfiguration}.
+     *
+     * @hide
+     */
+    public @Usage long getUsage() {
+        return mUsage;
+    }
+
+    /**
+     * Get the surface type associated with this {@link OutputConfiguration}.
+     *
+     * @return The surface type associated with this {@link OutputConfiguration}.
+     *
+     * @see #SURFACE_TYPE_SURFACE_VIEW
+     * @see #SURFACE_TYPE_SURFACE_TEXTURE
+     * @see #SURFACE_TYPE_MEDIA_RECORDER
+     * @see #SURFACE_TYPE_MEDIA_CODEC
+     * @see #SURFACE_TYPE_IMAGE_READER
+     * @see #SURFACE_TYPE_UNKNOWN
+     * @hide
+     */
+    public int getSurfaceType() {
+        return mSurfaceType;
+    }
+
+    /**
+     * Get the sensor pixel modes associated with this {@link OutputConfiguration}.
+     *
+     * @return List of {@link #SensorPixelMode} associated with this {@link OutputConfiguration}.
+     *
+     * @hide
+     */
+    public @NonNull List<Integer> getSensorPixelModes() {
+        return mSensorPixelModesUsed;
+    }
+
+     /**
+     * Get the sharing mode associated with this {@link OutputConfiguration}.
+     *
+     * @return true if surface sharing is enabled with this {@link OutputConfiguration}.
+     *
+     * @hide
+     */
+    public boolean isShared() {
+        return mIsShared;
+    }
+
+    /**
+     * Get the dataspace associated with this {@link OutputConfiguration}.
+     *
+     * @return {@link Dataspace#NamedDataSpace} for this {@link OutputConfiguration}.
+     *
+     * @hide
+     */
+    public @NamedDataSpace int getConfiguredDataspace() {
+        return mConfiguredDataspace;
+    }
+
+    /**
      * Get the physical camera ID associated with this {@link OutputConfiguration}.
      *
      * <p>If this OutputConfiguration isn't targeting a physical camera of a logical
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 50c6b5b..82aa64b 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.graphics.ColorSpace;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
@@ -78,6 +79,19 @@
         CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED;
 
     /**
+     * A shared session type containing instances of {@link OutputConfiguration} from a set of
+     * predefined stream configurations. A shared session can be shared among multiple clients.
+     * Shared session does not have any {@link InputConfiguration} as it does not support
+     * reprocessable sessions.
+     *
+     * @see CameraDevice#createCaptureSession(SessionConfiguration)
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+    @SystemApi
+    public static final int SESSION_SHARED = CameraDevice.SESSION_OPERATION_MODE_SHARED;
+
+    /**
      * First vendor-specific session mode
      * @hide
      */
diff --git a/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java
new file mode 100644
index 0000000..cdcc92c
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.graphics.ColorSpace;
+import android.graphics.ImageFormat.Format;
+import android.hardware.DataSpace.NamedDataSpace;
+import android.hardware.HardwareBuffer.Usage;
+import android.hardware.camera2.params.OutputConfiguration.MirrorMode;
+import android.hardware.camera2.params.OutputConfiguration.StreamUseCase;
+import android.hardware.camera2.params.OutputConfiguration.TimestampBase;
+import android.util.Log;
+import android.util.Size;
+
+import com.android.internal.camera.flags.Flags;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Immutable class to store the shared session configuration
+ * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraSharedCaptureSession capture session} using
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)} and
+ * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED
+ * shared capture session} when camera has been opened in shared mode using
+ * {@link #openSharedCamera(String, Executor, StateCallback)}.
+ *
+ * <p>This is the authoritative list for all output configurations that are supported by a camera
+ * device when opened in shared mode.</p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} key and the
+ * {@link CameraCharacteristics#get} method.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * StreamConfigurationMap configs = characteristics.get(
+ *         CameraCharacteristics.SHARED_SESSION_CONFIGURATION);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#SHARED_SESSION_CONFIGURATION
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
+ * @see SessionConfiguration#SESSION_SHARED
+ * @see CameraManager#openSharedCamera(String, Executor, StateCallback)
+ *
+ *  @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT)
+public final class SharedSessionConfiguration {
+    private static final String TAG = "SharedSessionConfiguration";
+    // Metadata android.info.availableSharedOutputConfigurations has list of shared output
+    // configurations. Each output configuration has minimum of 11 entries of size long
+    // followed by the physical camera id if present.
+    // See android.info.availableSharedOutputConfigurations for details.
+    private static final int SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES = 11;
+    /**
+     * Immutable class to store shared output stream information.
+     */
+    public static final class SharedOutputConfiguration {
+        private final int mSurfaceType;
+        private final Size mSize;
+        private final int mFormat;
+        private final int mDataspace;
+        private final long mStreamUseCase;
+        private String mPhysicalCameraId;
+        private final long mUsage;
+        private int mTimestampBase;
+        private int mMirrorMode;
+        private boolean mReadoutTimestampEnabled;
+
+        /**
+         * Create a new {@link SharedOutputConfiguration}.
+         *
+         * @param surfaceType Surface Type for this output configuration.
+         * @param sz Size for this output configuration.
+         * @param format {@link android.graphics.ImageFormat#Format} associated with this
+         *         {@link OutputConfiguration}.
+         * @param mirrorMode  {@link OutputConfiguration#MirrorMode} for this output configuration.
+         * @param readoutTimeStampEnabled  Flag indicating whether readout timestamp is enabled
+         *         for this output configuration.
+         * @param timestampBase {@link OutputConfiguration#TimestampBase} for this output
+         *         configuration.
+         * @param dataspace {@link Dataspace#NamedDataSpace} for this output configuration.
+         * @param usage   {@link HardwareBuffer#Usage} for this output configuration.
+         * @param streamUseCase {@link OutputConfiguration#StreamUseCase} for this output
+         *         configuration.
+         * @param physicalCamId Physical Camera Id for this output configuration.
+         *
+         * @hide
+         */
+        public SharedOutputConfiguration(int surfaceType, @NonNull Size sz, @Format int format,
+                @MirrorMode int mirrorMode, boolean readoutTimeStampEnabled,
+                @TimestampBase int timestampBase, @NamedDataSpace int dataspace, @Usage long usage,
+                @StreamUseCase long streamUseCase, @Nullable String physicalCamId) {
+            mSurfaceType = surfaceType;
+            mSize = sz;
+            mFormat = format;
+            mMirrorMode = mirrorMode;
+            mReadoutTimestampEnabled = readoutTimeStampEnabled;
+            mTimestampBase = timestampBase;
+            mDataspace = dataspace;
+            mUsage = usage;
+            mStreamUseCase = streamUseCase;
+            mPhysicalCameraId = physicalCamId;
+        }
+
+        /**
+         * Returns the surface type configured for the shared output configuration.
+         * @return  SURFACE_TYPE_UNKNOWN = -1
+         *          SURFACE_TYPE_SURFACE_VIEW = 0
+         *          SURFACE_TYPE_SURFACE_TEXTURE = 1
+         *          SURFACE_TYPE_MEDIA_RECORDER = 2
+         *          SURFACE_TYPE_MEDIA_CODEC = 3
+         *          SURFACE_TYPE_IMAGE_READER = 4
+         */
+        public int getSurfaceType() {
+            return mSurfaceType;
+        }
+
+        /**
+         * Returns the format of the shared output configuration.
+         * @return format The format of the configured output. This must be one of the
+         *     {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
+         *     constants. Note that not all formats are supported by the camera device.
+         */
+        public @Format int getFormat() {
+            return mFormat;
+        }
+
+        /**
+         * Returns the configured size for the shared output configuration.
+         * @return surfaceSize Size for the shared output configuration
+         *
+         */
+        public @NonNull Size getSize() {
+            return mSize;
+        }
+
+        /**
+         * Return datatspace configured for the shared output configuration.
+         *
+         * @return {@link Dataspace#NamedDataSpace} configured for shared session
+         */
+        public @NamedDataSpace int getDataspace() {
+            return mDataspace;
+        }
+
+        /**
+         * Get the  mirroring mode configured for the shared output configuration.
+         *
+         * @return {@link OutputConfiguration#MirrorMode} configured for the shared session
+         */
+        public @MirrorMode int getMirrorMode() {
+            return mMirrorMode;
+        }
+
+        /**
+         * Get the stream use case configured for the shared output configuration.
+         *
+         * @return {@link OutputConfiguration#StreamUseCase} configured for the shared session
+         */
+        public @StreamUseCase long getStreamUseCase() {
+            return mStreamUseCase;
+        }
+
+        /**
+         * Get the timestamp base configured for the shared output configuration.
+         *
+         * @return {@link OutputConfiguration#TimestampBase} configured for the shared session
+         */
+        public @TimestampBase int getTimestampBase() {
+            return mTimestampBase;
+        }
+
+        /** Whether readout timestamp is used for this shared output configuration.
+         *
+         */
+        public boolean isReadoutTimestampEnabled() {
+            return mReadoutTimestampEnabled;
+        }
+
+        /** Returns the usage if set for this shared output configuration.
+         *
+         * @return {@link HardwareBuffer#Usage} flags if set for shared output configuration with
+         *         the ImageReader output surface.
+         */
+        public @Usage long getUsage() {
+            return mUsage;
+        }
+
+        public @Nullable String getPhysicalCameraId() {
+            return mPhysicalCameraId;
+        }
+    }
+
+    /**
+     * Create a new {@link SharedSessionConfiguration}.
+     *
+     * <p>The array parameters ownership is passed to this object after creation; do not
+     * write to them after this constructor is invoked.</p>
+     *
+     * @param sharedColorSpace the colorspace to be used for the shared output configurations.
+     * @param sharedOutputConfigurations a non-{@code null} array of metadata
+     *                                  android.info.availableSharedOutputConfigurations
+     *
+     * @hide
+     */
+    public SharedSessionConfiguration(int sharedColorSpace,
+            @NonNull long[] sharedOutputConfigurations) {
+        mColorSpace = sharedColorSpace;
+        byte physicalCameraIdLen;
+        int surfaceType, width, height, format, mirrorMode, timestampBase, dataspace;
+        long usage, streamUseCase;
+        boolean isReadOutTimestampEnabled;
+        // Parse metadata android.info.availableSharedOutputConfigurations which contains
+        // list of shared output configurations.
+        int numOfEntries = sharedOutputConfigurations.length;
+        int i = 0;
+        while (numOfEntries >= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES) {
+            surfaceType = (int) sharedOutputConfigurations[i];
+            width = (int) sharedOutputConfigurations[i + 1];
+            height = (int) sharedOutputConfigurations[i + 2];
+            format = (int) sharedOutputConfigurations[i + 3];
+            mirrorMode = (int) sharedOutputConfigurations[i + 4];
+            isReadOutTimestampEnabled = (sharedOutputConfigurations[i + 5] != 0);
+            timestampBase = (int) sharedOutputConfigurations[i + 6];
+            dataspace = (int) sharedOutputConfigurations[i + 7];
+            usage = sharedOutputConfigurations[i + 8];
+            streamUseCase = sharedOutputConfigurations[i + 9];
+            physicalCameraIdLen = (byte) sharedOutputConfigurations[i + 10];
+            numOfEntries -= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES;
+            i += SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES;
+            if (numOfEntries < physicalCameraIdLen) {
+                Log.e(TAG, "Number of remaining data in shared configuration is less than"
+                        + " physical camera id length . Malformed metadata"
+                        + " android.info.availableSharedOutputConfigurations.");
+                break;
+            }
+            StringBuilder physicalCameraId =  new StringBuilder();
+            long asciiValue;
+            for (int j = 0; j < physicalCameraIdLen; j++) {
+                asciiValue = sharedOutputConfigurations[i + j];
+                if (asciiValue == 0) { // Check for null terminator
+                    break;
+                }
+                physicalCameraId.append((char) asciiValue);
+            }
+            SharedOutputConfiguration outputInfo;
+            outputInfo = new SharedOutputConfiguration(surfaceType, new Size(width, height),
+                    format,  mirrorMode, isReadOutTimestampEnabled, timestampBase,
+                    dataspace, usage, streamUseCase, physicalCameraId.toString());
+            mOutputStreamConfigurations.add(outputInfo);
+            i += physicalCameraIdLen;
+            numOfEntries -= physicalCameraIdLen;
+        }
+        if (numOfEntries != 0) {
+            Log.e(TAG, "Unexpected entries left in shared output configuration."
+                    + " Malformed metadata android.info.availableSharedOutputConfigurations.");
+        }
+    }
+
+    /**
+     * Return the shared session color space which is configured.
+     *
+     * @return the shared session color space
+     */
+    @SuppressLint("MethodNameUnits")
+    public @Nullable ColorSpace getColorSpace() {
+        if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+            return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+        } else {
+            return null;
+        }
+    }
+    /**
+     * Get information about each shared output configuarion in the shared session.
+     *
+     * @return Non-modifiable list of output configuration.
+     *
+     */
+    public @NonNull List<SharedOutputConfiguration> getOutputStreamsInformation() {
+        return Collections.unmodifiableList(mOutputStreamConfigurations);
+    }
+
+    private int mColorSpace;
+    private final ArrayList<SharedOutputConfiguration> mOutputStreamConfigurations =
+            new ArrayList<SharedOutputConfiguration>();
+}
+
diff --git a/core/java/android/hardware/contexthub/HubDiscoveryInfo.java b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java
new file mode 100644
index 0000000..875c4b4
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.hardware.location.ContextHubManager;
+
+/**
+ * Class that represents the result of from an hub endpoint discovery.
+ *
+ * <p>The type is returned from an endpoint discovery query via {@link
+ * ContextHubManager#findEndpoints}. Application may use the values {@link #getHubEndpointInfo} to
+ * retrieve the {@link HubEndpointInfo} that describes the endpoint that matches the query. The
+ * class provides flexibility in returning more information (e.g. service provided by the endpoint)
+ * in addition to the information about the endpoint.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubDiscoveryInfo {
+    // TODO(b/375487784): Add ServiceInfo to the result.
+    android.hardware.contexthub.HubEndpointInfo mEndpointInfo;
+
+    /**
+     * Constructor for internal use.
+     *
+     * @hide
+     */
+    public HubDiscoveryInfo(android.hardware.contexthub.HubEndpointInfo endpointInfo) {
+        mEndpointInfo = endpointInfo;
+    }
+
+    /** Get the {@link android.hardware.contexthub.HubEndpointInfo} for the endpoint found. */
+    @NonNull
+    public HubEndpointInfo getHubEndpointInfo() {
+        return mEndpointInfo;
+    }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
new file mode 100644
index 0000000..823cc7d
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.content.Context;
+import android.hardware.location.IContextHubService;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * An object representing an endpoint exposed to ContextHub and VendorHub. The object encapsulates
+ * the lifecycle and message callbacks for an endpoint.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpoint {
+    private static final String TAG = "HubEndpoint";
+
+    private final Object mLock = new Object();
+    private final HubEndpointInfo mPendingHubEndpointInfo;
+    @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback;
+    @Nullable private final IHubEndpointMessageCallback mMessageCallback;
+    @NonNull private final Executor mLifecycleCallbackExecutor;
+    @NonNull private final Executor mMessageCallbackExecutor;
+
+    @GuardedBy("mLock")
+    private final SparseArray<HubEndpointSession> mActiveSessions = new SparseArray<>();
+
+    private final IContextHubEndpointCallback mServiceCallback =
+            new IContextHubEndpointCallback.Stub() {
+                @Override
+                public void onSessionOpenRequest(int sessionId, HubEndpointInfo initiator)
+                        throws RemoteException {
+                    HubEndpointSession activeSession;
+                    synchronized (mLock) {
+                        activeSession = mActiveSessions.get(sessionId);
+                        // TODO(b/378974199): Consider refactor these assertions
+                        if (activeSession != null) {
+                            Log.i(
+                                    TAG,
+                                    "onSessionOpenComplete: session already exists, id="
+                                            + sessionId);
+                            return;
+                        }
+                    }
+
+                    if (mLifecycleCallback != null) {
+                        mLifecycleCallbackExecutor.execute(
+                                () ->
+                                        processSessionOpenRequestResult(
+                                                sessionId,
+                                                initiator,
+                                                mLifecycleCallback.onSessionOpenRequest(
+                                                        initiator)));
+                    }
+                }
+
+                private void processSessionOpenRequestResult(
+                        int sessionId, HubEndpointInfo initiator, HubEndpointSessionResult result) {
+                    if (result == null) {
+                        throw new IllegalArgumentException(
+                                "HubEndpointSessionResult shouldn't be null.");
+                    }
+
+                    if (result.isAccepted()) {
+                        acceptSession(sessionId, initiator);
+                    } else {
+                        Log.i(
+                                TAG,
+                                "Session "
+                                        + sessionId
+                                        + " from "
+                                        + initiator
+                                        + " was rejected, reason="
+                                        + result.getReason());
+                        rejectSession(sessionId);
+                    }
+                }
+
+                private void acceptSession(int sessionId, HubEndpointInfo initiator) {
+                    if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+                        // No longer registered?
+                        return;
+                    }
+
+                    // Retrieve the active session
+                    HubEndpointSession activeSession;
+                    synchronized (mLock) {
+                        activeSession = mActiveSessions.get(sessionId);
+                        // TODO(b/378974199): Consider refactor these assertions
+                        if (activeSession != null) {
+                            Log.e(
+                                    TAG,
+                                    "onSessionOpenRequestResult: session already exists, id="
+                                            + sessionId);
+                            return;
+                        }
+
+                        activeSession =
+                                new HubEndpointSession(
+                                        sessionId,
+                                        HubEndpoint.this,
+                                        mAssignedHubEndpointInfo,
+                                        initiator);
+                        try {
+                            // oneway call to notify system service that the request is completed
+                            mServiceToken.openSessionRequestComplete(sessionId);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "onSessionOpenRequestResult: ", e);
+                            return;
+                        }
+
+                        mActiveSessions.put(sessionId, activeSession);
+                    }
+
+                    // Execute the callback
+                    activeSession.setOpened();
+                    if (mLifecycleCallback != null) {
+                        final HubEndpointSession finalActiveSession = activeSession;
+                        mLifecycleCallbackExecutor.execute(
+                                () -> mLifecycleCallback.onSessionOpened(finalActiveSession));
+                    }
+                }
+
+                private void rejectSession(int sessionId) {
+                    if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+                        // No longer registered?
+                        return;
+                    }
+
+                    try {
+                        mServiceToken.closeSession(
+                                sessionId,
+                                IHubEndpointLifecycleCallback
+                                        .REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
+                    } catch (RemoteException e) {
+                        e.rethrowFromSystemServer();
+                    }
+                }
+
+                @Override
+                public void onSessionOpenComplete(int sessionId) throws RemoteException {
+                    final HubEndpointSession activeSession;
+
+                    // Retrieve the active session
+                    synchronized (mLock) {
+                        activeSession = mActiveSessions.get(sessionId);
+                    }
+                    // TODO(b/378974199): Consider refactor these assertions
+                    if (activeSession == null) {
+                        Log.i(
+                                TAG,
+                                "onSessionOpenComplete: no pending session open request? id="
+                                        + sessionId);
+                        return;
+                    }
+
+                    // Execute the callback
+                    activeSession.setOpened();
+                    if (mLifecycleCallback != null) {
+                        mLifecycleCallbackExecutor.execute(
+                                () -> mLifecycleCallback.onSessionOpened(activeSession));
+                    }
+                }
+
+                @Override
+                public void onSessionClosed(int sessionId, int reason) throws RemoteException {
+                    final HubEndpointSession activeSession;
+
+                    // Retrieve the active session
+                    synchronized (mLock) {
+                        activeSession = mActiveSessions.get(sessionId);
+                    }
+                    // TODO(b/378974199): Consider refactor these assertions
+                    if (activeSession == null) {
+                        Log.i(TAG, "onSessionClosed: session not active, id=" + sessionId);
+                        return;
+                    }
+
+                    // Execute the callback
+                    if (mLifecycleCallback != null) {
+                        mLifecycleCallbackExecutor.execute(
+                                () -> {
+                                    mLifecycleCallback.onSessionClosed(activeSession, reason);
+
+                                    // Remove the session object first to call
+                                    activeSession.setClosed();
+                                    synchronized (mLock) {
+                                        mActiveSessions.remove(sessionId);
+                                    }
+                                });
+                    }
+                }
+
+                @Override
+                public void onMessageReceived(int sessionId, HubMessage message)
+                        throws RemoteException {
+                    final HubEndpointSession activeSession;
+
+                    // Retrieve the active session
+                    synchronized (mLock) {
+                        activeSession = mActiveSessions.get(sessionId);
+                    }
+                    if (activeSession == null) {
+                        Log.i(TAG, "onMessageReceived: session not active, id=" + sessionId);
+                    }
+
+                    if (activeSession == null || mMessageCallback == null) {
+                        if (message.getDeliveryParams().isResponseRequired()) {
+                            try {
+                                mServiceToken.sendMessageDeliveryStatus(
+                                        sessionId,
+                                        message.getMessageSequenceNumber(),
+                                        ErrorCode.DESTINATION_NOT_FOUND);
+                            } catch (RemoteException e) {
+                                e.rethrowFromSystemServer();
+                            }
+                        }
+                        return;
+                    }
+
+                    // Execute the callback
+                    mMessageCallbackExecutor.execute(
+                            () -> {
+                                mMessageCallback.onMessageReceived(activeSession, message);
+                                if (message.getDeliveryParams().isResponseRequired()) {
+                                    try {
+                                        mServiceToken.sendMessageDeliveryStatus(
+                                                sessionId,
+                                                message.getMessageSequenceNumber(),
+                                                ErrorCode.OK);
+                                    } catch (RemoteException e) {
+                                        e.rethrowFromSystemServer();
+                                    }
+                                }
+                            });
+                }
+            };
+
+    /** Binder returned from system service, non-null while registered. */
+    @Nullable private IContextHubEndpoint mServiceToken;
+
+    /** HubEndpointInfo with the assigned endpoint id from system service. */
+    @Nullable private HubEndpointInfo mAssignedHubEndpointInfo;
+
+    private HubEndpoint(
+            @NonNull HubEndpointInfo pendingEndpointInfo,
+            @Nullable IHubEndpointLifecycleCallback endpointLifecycleCallback,
+            @NonNull Executor lifecycleCallbackExecutor,
+            @Nullable IHubEndpointMessageCallback endpointMessageCallback,
+            @NonNull Executor messageCallbackExecutor) {
+        mPendingHubEndpointInfo = pendingEndpointInfo;
+
+        mLifecycleCallback = endpointLifecycleCallback;
+        mLifecycleCallbackExecutor = lifecycleCallbackExecutor;
+        mMessageCallback = endpointMessageCallback;
+        mMessageCallbackExecutor = messageCallbackExecutor;
+    }
+
+    /** @hide */
+    public void register(IContextHubService service) {
+        // TODO(b/378974199): Consider refactor these assertions
+        if (mServiceToken != null) {
+            // Already registered
+            return;
+        }
+        try {
+            IContextHubEndpoint serviceToken =
+                    service.registerEndpoint(mPendingHubEndpointInfo, mServiceCallback);
+            mAssignedHubEndpointInfo = serviceToken.getAssignedHubEndpointInfo();
+            mServiceToken = serviceToken;
+        } catch (RemoteException e) {
+            Log.e(TAG, "registerEndpoint: failed to register endpoint", e);
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void unregister() {
+        IContextHubEndpoint serviceToken = mServiceToken;
+        // TODO(b/378974199): Consider refactor these assertions
+        if (serviceToken == null) {
+            // Not yet registered
+            return;
+        }
+
+        try {
+            synchronized (mLock) {
+                // Don't call HubEndpointSession.close() here.
+                for (int i = 0; i < mActiveSessions.size(); i++) {
+                    mActiveSessions.get(mActiveSessions.keyAt(i)).setClosed();
+                }
+                mActiveSessions.clear();
+            }
+            mServiceToken.unregister();
+        } catch (RemoteException e) {
+            Log.e(TAG, "unregisterEndpoint: failed to unregister endpoint", e);
+            e.rethrowFromSystemServer();
+        } finally {
+            mServiceToken = null;
+            mAssignedHubEndpointInfo = null;
+        }
+    }
+
+    /** @hide */
+    public void openSession(HubEndpointInfo destinationInfo) {
+        // TODO(b/378974199): Consider refactor these assertions
+        if (mServiceToken == null || mAssignedHubEndpointInfo == null) {
+            // No longer registered?
+            return;
+        }
+
+        HubEndpointSession newSession;
+        try {
+            // Request system service to assign session id.
+            int sessionId = mServiceToken.openSession(destinationInfo);
+
+            // Save the newly created session
+            synchronized (mLock) {
+                newSession =
+                        new HubEndpointSession(
+                                sessionId,
+                                HubEndpoint.this,
+                                destinationInfo,
+                                mAssignedHubEndpointInfo);
+                mActiveSessions.put(sessionId, newSession);
+            }
+        } catch (RemoteException e) {
+            // Move this to toString
+            Log.e(TAG, "openSession: failed to open session to " + destinationInfo, e);
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void closeSession(HubEndpointSession session) {
+        IContextHubEndpoint serviceToken = mServiceToken;
+        // TODO(b/378974199): Consider refactor these assertions
+        if (serviceToken == null || mAssignedHubEndpointInfo == null) {
+            // Not registered
+            return;
+        }
+
+        synchronized (mLock) {
+            if (!mActiveSessions.contains(session.getId())) {
+                // Already closed?
+                return;
+            }
+            session.setClosed();
+            mActiveSessions.remove(session.getId());
+        }
+
+        try {
+            // Oneway notification to system service
+            serviceToken.closeSession(
+                    session.getId(),
+                    IHubEndpointLifecycleCallback.REASON_CLOSE_ENDPOINT_SESSION_REQUESTED);
+        } catch (RemoteException e) {
+            Log.e(TAG, "closeSession: failed to close session " + session, e);
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void sendMessage(
+            HubEndpointSession session,
+            HubMessage message,
+            @Nullable IContextHubTransactionCallback transactionCallback) {
+        IContextHubEndpoint serviceToken = mServiceToken;
+        if (serviceToken == null) {
+            // Not registered
+            return;
+        }
+
+        try {
+            serviceToken.sendMessage(session.getId(), message, transactionCallback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendMessage: failed to send message session=" + session, e);
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    @Nullable
+    public String getTag() {
+        return mPendingHubEndpointInfo.getTag();
+    }
+
+    @Nullable
+    public IHubEndpointLifecycleCallback getLifecycleCallback() {
+        return mLifecycleCallback;
+    }
+
+    @Nullable
+    public IHubEndpointMessageCallback getMessageCallback() {
+        return mMessageCallback;
+    }
+
+    /** Builder for a {@link HubEndpoint} object. */
+    public static final class Builder {
+        private final String mPackageName;
+
+        @Nullable private IHubEndpointLifecycleCallback mLifecycleCallback;
+
+        @NonNull private Executor mLifecycleCallbackExecutor;
+
+        @Nullable private IHubEndpointMessageCallback mMessageCallback;
+        @NonNull private Executor mMessageCallbackExecutor;
+
+        @Nullable private String mTag;
+
+        /** Create a builder for {@link HubEndpoint} */
+        public Builder(@NonNull Context context) {
+            mPackageName = context.getPackageName();
+            mLifecycleCallbackExecutor = context.getMainExecutor();
+            mMessageCallbackExecutor = context.getMainExecutor();
+        }
+
+        /**
+         * Set a tag string. The tag can be used to further identify the creator of the endpoint.
+         * Endpoints created by the same package share the same name but should have different tags.
+         */
+        @NonNull
+        public Builder setTag(@NonNull String tag) {
+            mTag = tag;
+            return this;
+        }
+
+        /** Attach a callback interface for lifecycle events for this Endpoint */
+        @NonNull
+        public Builder setLifecycleCallback(
+                @NonNull IHubEndpointLifecycleCallback lifecycleCallback) {
+            mLifecycleCallback = lifecycleCallback;
+            return this;
+        }
+
+        /**
+         * Attach a callback interface for lifecycle events for this Endpoint with a specified
+         * executor
+         */
+        @NonNull
+        public Builder setLifecycleCallback(
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull IHubEndpointLifecycleCallback lifecycleCallback) {
+            mLifecycleCallbackExecutor = executor;
+            mLifecycleCallback = lifecycleCallback;
+            return this;
+        }
+
+        /** Attach a callback interface for message events for this Endpoint */
+        @NonNull
+        public Builder setMessageCallback(@NonNull IHubEndpointMessageCallback messageCallback) {
+            mMessageCallback = messageCallback;
+            return this;
+        }
+
+        /**
+         * Attach a callback interface for message events for this Endpoint with a specified
+         * executor
+         */
+        @NonNull
+        public Builder setMessageCallback(
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull IHubEndpointMessageCallback messageCallback) {
+            mMessageCallbackExecutor = executor;
+            mMessageCallback = messageCallback;
+            return this;
+        }
+
+        /** Build the {@link HubEndpoint} object. */
+        @NonNull
+        public HubEndpoint build() {
+            return new HubEndpoint(
+                    new HubEndpointInfo(mPackageName, mTag),
+                    mLifecycleCallback,
+                    mLifecycleCallbackExecutor,
+                    mMessageCallback,
+                    mMessageCallbackExecutor);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
similarity index 76%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to core/java/android/hardware/contexthub/HubEndpointInfo.aidl
index e4ccc2c..025b2b1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
@@ -14,10 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.hardware.contexthub;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/** @hide */
+parcelable HubEndpointInfo;
diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.java b/core/java/android/hardware/contexthub/HubEndpointInfo.java
new file mode 100644
index 0000000..ed8ff29
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+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;
+
+/**
+ * Parcelable representing an endpoint from ContextHub or VendorHub.
+ *
+ * <p>HubEndpointInfo contains information about an endpoint, including its name, tag and other
+ * information. A HubEndpointInfo object can be used to accurately identify a specific endpoint.
+ * Application can use this object to identify and describe an endpoint.
+ *
+ * <p>See: {@link android.hardware.location.ContextHubManager#findEndpoints} for how to retrieve
+ * {@link HubEndpointInfo} for endpoints on a hub.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubEndpointInfo implements Parcelable {
+    /**
+     * A unique identifier for one endpoint. A unique identifier for one endpoint consists of two
+     * parts: (1) a unique long number for a hub and (2) a long number for the endpoint, unique
+     * within a hub. This class overrides equality methods and can be used to compare if two
+     * endpoints are the same.
+     */
+    public static class HubEndpointIdentifier {
+        private final long mEndpointId;
+        private final long mHubId;
+
+        /** @hide */
+        public HubEndpointIdentifier(long hubId, long endpointId) {
+            mEndpointId = endpointId;
+            mHubId = hubId;
+        }
+
+        /** @hide */
+        public HubEndpointIdentifier(android.hardware.contexthub.EndpointId halEndpointId) {
+            mEndpointId = halEndpointId.id;
+            mHubId = halEndpointId.hubId;
+        }
+
+        /** Get the endpoint portion of the identifier. */
+        public long getEndpoint() {
+            return mEndpointId;
+        }
+
+        /** Get the hub portion of the identifier. */
+        public long getHub() {
+            return mHubId;
+        }
+
+        /**
+         * Create an invalid endpoint id, to represent endpoint that are not yet registered with the
+         * HAL.
+         *
+         * @hide
+         */
+        public static HubEndpointIdentifier invalid() {
+            return new HubEndpointIdentifier(
+                    android.hardware.contexthub.HubInfo.HUB_ID_INVALID,
+                    android.hardware.contexthub.EndpointId.ENDPOINT_ID_INVALID);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mEndpointId, mHubId);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof HubEndpointIdentifier other)) {
+                return false;
+            }
+            if (other.mHubId != mHubId) {
+                return false;
+            }
+            return other.mEndpointId == mEndpointId;
+        }
+    }
+
+    private final HubEndpointIdentifier mId;
+    private final String mName;
+    @Nullable private final String mTag;
+
+    // TODO(b/375487784): Add Service/version and other information to this object
+
+    /** @hide */
+    public HubEndpointInfo(android.hardware.contexthub.EndpointInfo endpointInfo) {
+        mId = new HubEndpointIdentifier(endpointInfo.id.hubId, endpointInfo.id.id);
+        mName = endpointInfo.name;
+        mTag = endpointInfo.tag;
+    }
+
+    /** @hide */
+    public HubEndpointInfo(String name, @Nullable String tag) {
+        mId = HubEndpointIdentifier.invalid();
+        mName = name;
+        mTag = tag;
+    }
+
+    private HubEndpointInfo(Parcel in) {
+        long hubId = in.readLong();
+        long endpointId = in.readLong();
+        mName = in.readString();
+        mTag = in.readString();
+
+        mId = new HubEndpointIdentifier(hubId, endpointId);
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeLong(mId.getHub());
+        dest.writeLong(mId.getEndpoint());
+        dest.writeString(mName);
+        dest.writeString(mTag);
+    }
+
+    /** Get a unique identifier for this endpoint. */
+    @NonNull
+    public HubEndpointIdentifier getIdentifier() {
+        return mId;
+    }
+
+    /** Get the human-readable name of this endpoint (for debugging purposes). */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Get the tag that further identifies the submodule that created this endpoint. For example, a
+     * single application could provide multiple endpoints. These endpoints will share the same
+     * name, but will have different tags. This tag can be used to identify the submodule within the
+     * application that provided the endpoint.
+     */
+    @Nullable
+    public String getTag() {
+        return mTag;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder out = new StringBuilder();
+        out.append("Endpoint [0x");
+        out.append(Long.toHexString(mId.getEndpoint()));
+        out.append("@ Hub 0x");
+        out.append(Long.toHexString(mId.getHub()));
+        out.append("] Name=");
+        out.append(mName);
+        out.append(", Tag=");
+        out.append(mTag);
+        return out.toString();
+    }
+
+    public static final @android.annotation.NonNull Creator<HubEndpointInfo> CREATOR =
+            new Creator<>() {
+                public HubEndpointInfo createFromParcel(Parcel in) {
+                    return new HubEndpointInfo(in);
+                }
+
+                public HubEndpointInfo[] newArray(int size) {
+                    return new HubEndpointInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java
new file mode 100644
index 0000000..5d6e2b5
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.ContextHubTransactionHelper;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.util.CloseGuard;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * An object representing a communication session between two different hub endpoints.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpointSession implements AutoCloseable {
+    private final CloseGuard mCloseGuard = new CloseGuard();
+
+    private final int mId;
+
+    @NonNull private final HubEndpoint mHubEndpoint;
+    @NonNull private final HubEndpointInfo mInitiator;
+    @NonNull private final HubEndpointInfo mDestination;
+
+    private final AtomicBoolean mIsClosed = new AtomicBoolean(true);
+
+    /** @hide */
+    HubEndpointSession(
+            int id,
+            @NonNull HubEndpoint hubEndpoint,
+            @NonNull HubEndpointInfo destination,
+            @NonNull HubEndpointInfo initiator) {
+        mId = id;
+        mHubEndpoint = hubEndpoint;
+        mDestination = destination;
+        mInitiator = initiator;
+    }
+
+    /**
+     * Send a message to the peer endpoint in this session.
+     *
+     * @param message The message object constructed with {@link HubMessage#createMessage}.
+     * @return For messages that does not require a response, the transaction will immediately
+     *     complete. For messages that requires a response, the transaction will complete after
+     *     receiving the response for the message.
+     */
+    @NonNull
+    public ContextHubTransaction<Void> sendMessage(@NonNull HubMessage message) {
+        if (mIsClosed.get()) {
+            throw new IllegalStateException("Session is already closed.");
+        }
+
+        boolean isResponseRequired = message.getDeliveryParams().isResponseRequired();
+        ContextHubTransaction<Void> ret =
+                new ContextHubTransaction<>(
+                        isResponseRequired
+                                ? ContextHubTransaction.TYPE_HUB_MESSAGE_REQUIRES_RESPONSE
+                                : ContextHubTransaction.TYPE_HUB_MESSAGE_DEFAULT);
+        if (!isResponseRequired) {
+            // If the message doesn't require acknowledgement, respond with success immediately
+            // TODO(b/379162322): Improve handling of synchronous failures.
+            mHubEndpoint.sendMessage(this, message, null);
+            ret.setResponse(
+                    new ContextHubTransaction.Response<>(
+                            ContextHubTransaction.RESULT_SUCCESS, null));
+        } else {
+            IContextHubTransactionCallback callback =
+                    ContextHubTransactionHelper.createTransactionCallback(ret);
+            // Sequence number will be assigned at the service
+            mHubEndpoint.sendMessage(this, message, callback);
+        }
+        return ret;
+    }
+
+    /** @hide */
+    public int getId() {
+        return mId;
+    }
+
+    /** @hide */
+    public void setOpened() {
+        mIsClosed.set(false);
+        mCloseGuard.open("close");
+    }
+
+    /** @hide */
+    public void setClosed() {
+        mIsClosed.set(true);
+        mCloseGuard.close();
+    }
+
+    /**
+     * Closes the connection for this session between an endpoint and the Context Hub Service.
+     *
+     * <p>When this function is invoked, the messaging associated with this session is invalidated.
+     * All futures messages targeted for this client are dropped.
+     */
+    public void close() {
+        if (!mIsClosed.getAndSet(true)) {
+            mCloseGuard.close();
+            mHubEndpoint.closeSession(this);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("Session [");
+        stringBuilder.append(mId);
+        stringBuilder.append("]: [");
+        stringBuilder.append(mInitiator);
+        stringBuilder.append("]->[");
+        stringBuilder.append(mDestination);
+        stringBuilder.append("]");
+        return stringBuilder.toString();
+    }
+
+    /** @hide */
+    protected void finalize() throws Throwable {
+        try {
+            // Note that guard could be null if the constructor threw.
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointSessionResult.java b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java
new file mode 100644
index 0000000..1f2bdb9
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+/**
+ * Return type of {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. The value determines
+ * whether a open session request from the remote is accepted or not.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubEndpointSessionResult {
+    private final boolean mAccepted;
+
+    @Nullable private final String mReason;
+
+    private HubEndpointSessionResult(boolean accepted, @Nullable String reason) {
+        mAccepted = accepted;
+        mReason = reason;
+    }
+
+    /**
+     * Retrieve the decision of the session request.
+     *
+     * @return Whether a session request was accepted or not, previously set with {@link #accept()}
+     *     or {@link #reject(String)}.
+     */
+    public boolean isAccepted() {
+        return mAccepted;
+    }
+
+    /**
+     * Retrieve the decision of the session request.
+     *
+     * @return The reason previously set in {@link #reject(String)}. If the result was {@link
+     *     #accept()}, the reason will be null.
+     */
+    @Nullable
+    public String getReason() {
+        return mReason;
+    }
+
+    /** Accept the request. */
+    @NonNull
+    public static HubEndpointSessionResult accept() {
+        return new HubEndpointSessionResult(true, null);
+    }
+
+    /**
+     * Reject the request with a reason.
+     *
+     * @param reason Reason why the request was rejected, for diagnostic purposes.
+     */
+    @NonNull
+    public static HubEndpointSessionResult reject(@NonNull String reason) {
+        return new HubEndpointSessionResult(false, reason);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/core/java/android/hardware/contexthub/HubMessage.aidl
similarity index 69%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to core/java/android/hardware/contexthub/HubMessage.aidl
index e4ccc2c..86afce2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/core/java/android/hardware/contexthub/HubMessage.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright 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.
@@ -14,10 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.hardware.contexthub;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/**
+ * @hide
+ */
+parcelable HubMessage;
diff --git a/core/java/android/hardware/contexthub/HubMessage.java b/core/java/android/hardware/contexthub/HubMessage.java
new file mode 100644
index 0000000..dc8a8c5
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubMessage.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+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 libcore.util.HexEncoding;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A class describing general messages send through the Context Hub Service.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubMessage implements Parcelable {
+    private static final int DEBUG_LOG_NUM_BYTES = 16;
+
+    private final int mMessageType;
+    private final byte[] mMessageBody;
+
+    private final DeliveryParams mDeliveryParams;
+    private int mMessageSequenceNumber;
+
+    /**
+     * Configurable options for message delivery. This option can be passed into {@link
+     * HubEndpointSession#sendMessage} to specify the behavior of message delivery.
+     */
+    public static class DeliveryParams {
+        private boolean mResponseRequired;
+
+        private DeliveryParams(boolean responseRequired) {
+            mResponseRequired = responseRequired;
+        }
+
+        /** Get the acknowledgement requirement. */
+        public boolean isResponseRequired() {
+            return mResponseRequired;
+        }
+
+        /**
+         * Set the response requirement for a message. Message sent with this option will have a
+         * {@link android.hardware.location.ContextHubTransaction.Response} when the peer received
+         * the message. Default is false.
+         */
+        @NonNull
+        public DeliveryParams setResponseRequired(boolean required) {
+            mResponseRequired = required;
+            return this;
+        }
+
+        /** Construct a default delivery option. */
+        @NonNull
+        public static DeliveryParams makeBasic() {
+            return new DeliveryParams(false);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder();
+            out.append("DeliveryParams[");
+            out.append("responseRequired = ").append(mResponseRequired);
+            out.append("]");
+            return out.toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mResponseRequired);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+
+            if (obj instanceof DeliveryParams other) {
+                return other.mResponseRequired == mResponseRequired;
+            }
+
+            return false;
+        }
+    }
+
+    private HubMessage(int messageType, byte[] messageBody, DeliveryParams deliveryParams) {
+        mMessageType = messageType;
+        mMessageBody = messageBody;
+        mDeliveryParams = deliveryParams;
+    }
+
+    /**
+     * Creates a HubMessage object to send to through an endpoint.
+     *
+     * @param messageType the endpoint & service dependent message type
+     * @param messageBody the byte array message contents
+     * @return the HubMessage object
+     */
+    @NonNull
+    public static HubMessage createMessage(int messageType, @NonNull byte[] messageBody) {
+        return new HubMessage(messageType, messageBody, DeliveryParams.makeBasic());
+    }
+
+    /**
+     * Creates a HubMessage object to send to through an endpoint.
+     *
+     * @param messageType the endpoint & service dependent message type
+     * @param messageBody the byte array message contents
+     * @param deliveryParams The message delivery parameters. See {@link HubMessage.DeliveryParams}
+     *     for more details.
+     * @return the HubMessage object
+     */
+    @NonNull
+    public static HubMessage createMessage(
+            int messageType, @NonNull byte[] messageBody, @NonNull DeliveryParams deliveryParams) {
+        return new HubMessage(messageType, messageBody, deliveryParams);
+    }
+
+    /**
+     * Retrieve the message type.
+     *
+     * @return the type of the message
+     */
+    public int getMessageType() {
+        return mMessageType;
+    }
+
+    /**
+     * Retrieve the body of the message. The body can be an empty byte array.
+     *
+     * @return the byte array contents of the message
+     */
+    @NonNull
+    public byte[] getMessageBody() {
+        return mMessageBody;
+    }
+
+    /**
+     * Retrieve the {@link DeliveryParams} object specifying the behavior of message delivery.
+     *
+     * @hide
+     */
+    public DeliveryParams getDeliveryParams() {
+        return mDeliveryParams;
+    }
+
+    /**
+     * Assign a message sequence number. This should only be called by the system service.
+     *
+     * @hide
+     */
+    public void setMessageSequenceNumber(int messageSequenceNumber) {
+        mMessageSequenceNumber = messageSequenceNumber;
+    }
+
+    /**
+     * Returns the message sequence number. The default value is 0.
+     *
+     * @return the message sequence number of the message
+     * @hide
+     */
+    public int getMessageSequenceNumber() {
+        return mMessageSequenceNumber;
+    }
+
+    private HubMessage(@NonNull Parcel in) {
+        mMessageType = in.readInt();
+
+        int msgSize = in.readInt();
+        mMessageBody = new byte[msgSize];
+        in.readByteArray(mMessageBody);
+
+        mDeliveryParams = DeliveryParams.makeBasic();
+        mDeliveryParams.setResponseRequired(in.readInt() == 1);
+        mMessageSequenceNumber = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mMessageType);
+
+        out.writeInt(mMessageBody.length);
+        out.writeByteArray(mMessageBody);
+
+        out.writeInt(mDeliveryParams.isResponseRequired() ? 1 : 0);
+        out.writeInt(mMessageSequenceNumber);
+    }
+
+    public static final @NonNull Creator<HubMessage> CREATOR =
+            new Creator<>() {
+                @Override
+                public HubMessage createFromParcel(Parcel in) {
+                    return new HubMessage(in);
+                }
+
+                @Override
+                public HubMessage[] newArray(int size) {
+                    return new HubMessage[size];
+                }
+            };
+
+    @NonNull
+    @Override
+    public String toString() {
+        int length = mMessageBody.length;
+
+        StringBuilder out = new StringBuilder();
+        out.append("HubMessage[type = ").append(mMessageType);
+        out.append(", length = ").append(mMessageBody.length);
+        out.append(", messageSequenceNumber = ").append(mMessageSequenceNumber);
+        out.append(", deliveryParams = ").append(mDeliveryParams);
+        out.append("](");
+
+        if (length > 0) {
+            out.append("data = 0x");
+        }
+        for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) {
+            out.append(HexEncoding.encodeToString(mMessageBody[i], true /* upperCase */));
+
+            if ((i + 1) % 4 == 0) {
+                out.append(" ");
+            }
+        }
+        if (length > DEBUG_LOG_NUM_BYTES) {
+            out.append("...");
+        }
+        out.append(")");
+
+        return out.toString();
+    }
+
+    @Override
+    public boolean equals(@Nullable Object object) {
+        if (object == this) {
+            return true;
+        }
+
+        boolean isEqual = false;
+        if (object instanceof HubMessage other) {
+            isEqual =
+                    (other.getMessageType() == mMessageType)
+                            && Arrays.equals(other.getMessageBody(), mMessageBody)
+                            && (other.getDeliveryParams().equals(mDeliveryParams))
+                            && (other.getMessageSequenceNumber() == mMessageSequenceNumber);
+        }
+
+        return isEqual;
+    }
+
+    @Override
+    public int hashCode() {
+        if (!Flags.fixApiCheck()) {
+            return super.hashCode();
+        }
+
+        return Objects.hash(
+                mMessageType,
+                Arrays.hashCode(mMessageBody),
+                mDeliveryParams,
+                mMessageSequenceNumber);
+    }
+}
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
new file mode 100644
index 0000000..a67b8de
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubMessage;
+import android.hardware.location.IContextHubTransactionCallback;
+
+/**
+ * @hide
+ */
+interface IContextHubEndpoint {
+    /**
+     * Retrieve the up-to-date EndpointInfo, with assigned endpoint id.
+     */
+    HubEndpointInfo getAssignedHubEndpointInfo();
+
+    /**
+     * Request system service to open a session with a specific destination.
+     *
+     * @param destination A valid HubEndpointInfo representing the destination.
+     *
+     * @throws IllegalArgumentException If the HubEndpointInfo is not valid.
+     * @throws IllegalStateException If there are too many opened sessions.
+     */
+    int openSession(in HubEndpointInfo destination);
+
+    /**
+     * Request system service to close a specific session
+     *
+     * @param sessionId An integer identifying the session, assigned by system service
+     * @param reason An integer identifying the reason
+     *
+     * @throws IllegalStateException If the session wasn't opened.
+     */
+    void closeSession(int sessionId, int reason);
+
+    /**
+     * Callback when a session is opened. This callback is the status callback for a previous
+     * IContextHubEndpointCallback.onSessionOpenRequest().
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         onSessionOpenRequest().
+     *
+     * @throws IllegalStateException If the session wasn't opened.
+     */
+    void openSessionRequestComplete(int sessionId);
+
+    /**
+     * Unregister this endpoint from the HAL, invalidate the EndpointInfo previously assigned.
+     */
+    void unregister();
+
+    /**
+     * Send a message parcelable to system service for a specific session.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+     * @param message The HubMessage parcelable that represents the message and its delivery options.
+     * @param transactionCallback Nullable. If the hub message requires a reply, the transactionCallback
+     *                            will be set to non-null.
+     */
+    void sendMessage(int sessionId, in HubMessage message,
+                     in @nullable IContextHubTransactionCallback transactionCallback);
+
+    /**
+     * Send a message delivery status to system service for a specific message
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+     * @param messageSeqNumber The message sequence number, this should match a previously received HubMessage.
+     * @param errorCode The message delivery status detail.
+     */
+    void sendMessageDeliveryStatus(int sessionId, int messageSeqNumber, byte errorCode);
+}
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl
new file mode 100644
index 0000000..7f5c601
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubMessage;
+
+/**
+  * @hide
+ */
+oneway interface IContextHubEndpointCallback {
+    /**
+     * Request from system service to open a session, requested by a specific initiator.
+     *
+     * @param sessionId An integer identifying the session, assigned by the initiator
+     * @param initiator HubEndpointInfo representing the requester
+     */
+    void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator);
+
+    /**
+     * Request from system service to close a specific session
+     *
+     * @param sessionId An integer identifying the session
+     * @param reason An integer identifying the reason
+     */
+    void onSessionClosed(int sessionId, int reason);
+
+    /**
+     * Notifies the system service that the session requested by IContextHubEndpoint.openSession
+     * is ready to use.
+     *
+     * @param sessionId The integer representing the communication session, previously set in
+     *         IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+     */
+    void onSessionOpenComplete(int sessionId);
+
+    /**
+     * Message notification from system service for a specific session
+
+     * @param sessionId The integer representing the communication session, previously set in
+     *         IContextHubEndpoint.openSession(). This id is assigned by the HAL.
+     * @param message The HubMessage parcelable that represents the message.
+     */
+    void onMessageReceived(int sessionId, in HubMessage message);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
new file mode 100644
index 0000000..5bd3c0e
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for listening to lifecycle events of a hub endpoint.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public interface IHubEndpointLifecycleCallback {
+    /** Unknown reason. */
+    int REASON_UNSPECIFIED = 0;
+
+    /** The peer rejected the request to open this endpoint session. */
+    int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3;
+
+    /** The peer closed this endpoint session. */
+    int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        REASON_UNSPECIFIED,
+        REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED,
+        REASON_CLOSE_ENDPOINT_SESSION_REQUESTED,
+    })
+    @interface EndpointLifecycleReason {}
+
+    /**
+     * Called when an endpoint is requesting a session be opened with another endpoint.
+     *
+     * @param requester The {@link HubEndpointInfo} object representing the requester
+     */
+    @NonNull
+    HubEndpointSessionResult onSessionOpenRequest(@NonNull HubEndpointInfo requester);
+
+    /**
+     * Called when a communication session is opened and ready to be used.
+     *
+     * @param session The {@link HubEndpointSession} object that can be used for communication
+     */
+    void onSessionOpened(@NonNull HubEndpointSession session);
+
+    /**
+     * Called when a communication session is requested to be closed, or the peer endpoint rejected
+     * the session open request.
+     *
+     * @param session The {@link HubEndpointSession} object that is now closed and shouldn't be
+     *     used.
+     * @param reason The reason why this session was closed.
+     */
+    void onSessionClosed(@NonNull HubEndpointSession session, @EndpointLifecycleReason int reason);
+}
diff --git a/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java
new file mode 100644
index 0000000..fde7017
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.contexthub;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+
+/**
+ * An interface used to deliver messages to an opened endpoint session.
+ *
+ * <p>This interface can be attached to an endpoint through {@link
+ * HubEndpoint.Builder#setMessageCallback} method. Methods in this interface will only be called
+ * when the endpoint is currently registered and has an open session. The endpoint will receive
+ * session lifecycle callbacks through {@link IHubEndpointLifecycleCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public interface IHubEndpointMessageCallback {
+    /**
+     * Callback interface for receiving messages for a particular endpoint session.
+     *
+     * @param session The session this message is sent through. Previously specified in a {@link
+     *     IHubEndpointLifecycleCallback#onSessionOpened(HubEndpointSession)} call.
+     * @param message The {@link HubMessage} object representing a message received by the endpoint
+     *     that registered this callback interface. This message is constructed by the
+     */
+    void onMessageReceived(@NonNull HubEndpointSession session, @NonNull HubMessage message);
+}
diff --git a/core/java/android/hardware/contexthub/OWNERS b/core/java/android/hardware/contexthub/OWNERS
new file mode 100644
index 0000000..a65a2bf
--- /dev/null
+++ b/core/java/android/hardware/contexthub/OWNERS
@@ -0,0 +1,2 @@
+# ContextHub team
+file:platform/system/chre:/OWNERS
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 28da644..25327a9 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -21,6 +21,8 @@
 import static android.view.Display.HdrCapabilities.HdrType;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.server.display.feature.flags.Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS;
+
 import android.Manifest;
 import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
@@ -59,6 +61,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.display.feature.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -100,6 +103,7 @@
     private final WeakDisplayCache mDisplayCache = new WeakDisplayCache();
 
     private int mDisplayIdToMirror = INVALID_DISPLAY;
+    private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
 
     /**
      * Broadcast receiver that indicates when the Wifi display status changes.
@@ -576,6 +580,8 @@
             EVENT_FLAG_DISPLAY_ADDED,
             EVENT_FLAG_DISPLAY_CHANGED,
             EVENT_FLAG_DISPLAY_REMOVED,
+            EVENT_FLAG_DISPLAY_REFRESH_RATE,
+            EVENT_FLAG_DISPLAY_STATE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventFlag {}
@@ -596,8 +602,8 @@
      *
      * @see #registerDisplayListener(DisplayListener, Handler, long)
      *
-     * @hide
      */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
     public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0;
 
     /**
@@ -605,8 +611,8 @@
      *
      * @see #registerDisplayListener(DisplayListener, Handler, long)
      *
-     * @hide
      */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
     public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1;
 
     /**
@@ -614,10 +620,27 @@
      *
      * @see #registerDisplayListener(DisplayListener, Handler, long)
      *
-     * @hide
      */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
     public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
 
+
+    /**
+     * Event flag to register for a display's refresh rate changes.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+    public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 3;
+
+    /**
+     * Event flag to register for a display state changes.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler, long)
+     */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+    public static final long EVENT_FLAG_DISPLAY_STATE = 1L << 4;
+
     /**
      * Event flag to register for a display's brightness changes. This notification is sent
      * through the {@link DisplayListener#onDisplayChanged} callback method. New brightness
@@ -787,9 +810,6 @@
      * if the listener should be invoked on the calling thread's looper.
      * @param eventFlags A bitmask of the event types for which this listener is subscribed.
      *
-     * @see #EVENT_FLAG_DISPLAY_ADDED
-     * @see #EVENT_FLAG_DISPLAY_CHANGED
-     * @see #EVENT_FLAG_DISPLAY_REMOVED
      * @see #registerDisplayListener(DisplayListener, Handler)
      * @see #unregisterDisplayListener
      *
@@ -806,18 +826,31 @@
      * Registers a display listener to receive notifications about given display event types.
      *
      * @param listener The listener to register.
+     * @param executor Executor for the thread that will be receiving the callbacks. Cannot be null.
+     * @param eventFlags A bitmask of the event types for which this listener is subscribed.
+     *
+     * @see #registerDisplayListener(DisplayListener, Handler)
+     * @see #unregisterDisplayListener
+     *
+     */
+    @FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+    public void registerDisplayListener(@NonNull Executor executor, @EventFlag long eventFlags,
+            @NonNull DisplayListener listener) {
+        mGlobal.registerDisplayListener(listener, executor,
+                mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0),
+                ActivityThread.currentPackageName());
+    }
+
+    /**
+     * Registers a display listener to receive notifications about given display event types.
+     *
+     * @param listener The listener to register.
      * @param handler The handler on which the listener should be invoked, or null
      * if the listener should be invoked on the calling thread's looper.
      * @param eventFlags A bitmask of the event types for which this listener is subscribed.
      * @param privateEventFlags A bitmask of the private event types for which this listener
      *                          is subscribed.
      *
-     * @see #EVENT_FLAG_DISPLAY_ADDED
-     * @see #EVENT_FLAG_DISPLAY_CHANGED
-     * @see #EVENT_FLAG_DISPLAY_REMOVED
-     * @see #PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS
-     * @see #PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED
-     * @see #PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED
      * @see #registerDisplayListener(DisplayListener, Handler)
      * @see #unregisterDisplayListener
      *
@@ -1582,6 +1615,17 @@
     }
 
     /**
+     * Returns whether this device supports Always On Display.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_IS_ALWAYS_ON_AVAILABLE_API)
+    public boolean isAlwaysOnDisplayCurrentlyAvailable() {
+        return getAmbientDisplayConfiguration().alwaysOnAvailableForUser(mContext.getUserId());
+    }
+
+    /**
      * Returns whether device supports seamless refresh rate switching.
      *
      * Match content frame rate setting has three options: seamless, non-seamless and never.
@@ -1643,6 +1687,15 @@
         }
     }
 
+    private AmbientDisplayConfiguration getAmbientDisplayConfiguration() {
+        synchronized (this) {
+            if (mAmbientDisplayConfiguration == null) {
+                mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
+            }
+        }
+        return mAmbientDisplayConfiguration;
+    }
+
     /**
      * Creates a VirtualDisplay that will mirror the content of displayIdToMirror
      * @param name The name for the virtual display
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 03b44f6..1e66bee 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -17,6 +17,7 @@
 package android.hardware.display;
 
 
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
 import static android.hardware.display.DisplayManager.EventFlag;
 import static android.Manifest.permission.MANAGE_DISPLAYS;
 import static android.view.Display.HdrCapabilities.HdrType;
@@ -62,6 +63,7 @@
 import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.feature.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -108,6 +110,8 @@
             EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED,
             EVENT_DISPLAY_CONNECTED,
             EVENT_DISPLAY_DISCONNECTED,
+            EVENT_DISPLAY_REFRESH_RATE_CHANGED,
+            EVENT_DISPLAY_STATE_CHANGED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DisplayEvent {}
@@ -119,6 +123,8 @@
     public static final int EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED = 5;
     public static final int EVENT_DISPLAY_CONNECTED = 6;
     public static final int EVENT_DISPLAY_DISCONNECTED = 7;
+    public static final int EVENT_DISPLAY_REFRESH_RATE_CHANGED = 8;
+    public static final int EVENT_DISPLAY_STATE_CHANGED = 9;
 
     @LongDef(prefix = {"INTERNAL_EVENT_DISPLAY"}, flag = true, value = {
             INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
@@ -127,6 +133,8 @@
             INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED,
             INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
             INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+            INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+            INTERNAL_EVENT_FLAG_DISPLAY_STATE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InternalEventFlag {}
@@ -137,6 +145,8 @@
     public static final long INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED = 1L << 3;
     public static final long INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED = 1L << 4;
     public static final long INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5;
+    public static final long INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 6;
+    public static final long INTERNAL_EVENT_FLAG_DISPLAY_STATE = 1L << 7;
 
     @UnsupportedAppUsage
     private static DisplayManagerGlobal sInstance;
@@ -179,9 +189,11 @@
     }
 
     private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache =
-            new PropertyInvalidatedCache<Integer, DisplayInfo>(
-                8, // size of display cache
-                CACHE_KEY_DISPLAY_INFO_PROPERTY) {
+            new PropertyInvalidatedCache<>(
+                new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+                .maxEntries(8).api(CACHE_KEY_DISPLAY_INFO_API).isolateUids(false),
+                CACHE_KEY_DISPLAY_INFO_API, null) {
+
                 @Override
                 public DisplayInfo recompute(Integer id) {
                     try {
@@ -1427,6 +1439,18 @@
                         mListener.onDisplayDisconnected(displayId);
                     }
                     break;
+                case EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+                    if ((mInternalEventFlagsMask
+                            & INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0) {
+                        mListener.onDisplayChanged(displayId);
+                    }
+                    break;
+                case EVENT_DISPLAY_STATE_CHANGED:
+                    if ((mInternalEventFlagsMask
+                            & INTERNAL_EVENT_FLAG_DISPLAY_STATE) != 0) {
+                        mListener.onDisplayChanged(displayId);
+                    }
+                    break;
             }
             if (DEBUG) {
                 Trace.endSection();
@@ -1493,18 +1517,17 @@
     }
 
     /**
-     * Name of the property containing a unique token which changes every time we update the
-     * system's display configuration.
+     * The API portion of the key that identifies the unique PropertyInvalidatedCache token which
+     * changes every time we update the system's display configuration.
      */
-    public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
-            PropertyInvalidatedCache.createSystemCacheKey("display_info");
+    private static final String CACHE_KEY_DISPLAY_INFO_API = "display_info";
 
     /**
      * Invalidates the contents of the display info cache for all applications. Can only
      * be called by system_server.
      */
     public static void invalidateLocalDisplayInfoCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY);
+        PropertyInvalidatedCache.invalidateCache(MODULE_SYSTEM, CACHE_KEY_DISPLAY_INFO_API);
     }
 
     /**
@@ -1566,6 +1589,10 @@
                 return "EVENT_DISPLAY_CONNECTED";
             case EVENT_DISPLAY_DISCONNECTED:
                 return "EVENT_DISPLAY_DISCONNECTED";
+            case EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+                return "EVENT_DISPLAY_REFRESH_RATE_CHANGED";
+            case EVENT_DISPLAY_STATE_CHANGED:
+                return "EVENT_DISPLAY_STATE_CHANGED";
         }
         return "UNKNOWN";
     }
@@ -1630,6 +1657,17 @@
             baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
         }
 
+        if (Flags.displayListenerPerformanceImprovements()) {
+            if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0) {
+                baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+            }
+
+            if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_STATE) != 0) {
+                baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE;
+            }
+        }
+
+
         return baseEventMask;
     }
 }
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index e349b81..f00c3a5 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -23,6 +23,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.graphics.PointF;
 import android.graphics.RectF;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -150,6 +151,138 @@
         }
     }
 
+    /**
+     * Rearranges the topology toward the positions given for each display. The width and height of
+     * each display, as well as the primary display, are not changed by this call.
+     * <p>
+     * Upon returning, the topology will be valid and normalized with each display as close to the
+     * requested positions as possible.
+     *
+     * @param newPos the desired positions (upper-left corner) of each display. The keys in the map
+     *               are the display IDs.
+     * @throws IllegalArgumentException if the keys in {@code positions} are not the exact display
+     *                                  IDs in this topology, no more, no less
+     */
+    public void rearrange(Map<Integer, PointF> newPos) {
+        var availableParents = new ArrayList<TreeNode>();
+
+        availableParents.addLast(mRoot);
+
+        var needsParent = allNodesIdMap();
+
+        // In the case of missing items, if this check doesn't detect it, a NPE will be thrown
+        // later.
+        if (needsParent.size() != newPos.size()) {
+            throw new IllegalArgumentException("newPos has wrong number of entries: " + newPos);
+        }
+
+        mRoot.mChildren.clear();
+        for (TreeNode n : needsParent.values()) {
+            n.mChildren.clear();
+        }
+
+        needsParent.remove(mRoot.mDisplayId);
+        // Start with a root island and add children to it one-by-one until the island consists of
+        // all the displays. The root island begins with only the root node, which has no
+        // parent. Then we greedily choose an optimal pairing of two nodes, consisting of a node
+        // from the island and a node not yet in the island. This is repeating until all nodes are
+        // in the island.
+        //
+        // The optimal pair is the pair which has the smallest deviation. The deviation consists of
+        // an x-axis component and a y-axis component, called xDeviation and yDeviation.
+        //
+        // The deviations are like distances but a little different. They are calculated in two
+        // steps. The first step calculates both axes in a similar way. The next step compares the
+        // two values and chooses which axis to attach along. Depending on which axis is chosen,
+        // the deviation for one axis is updated. See below for details.
+        while (!needsParent.isEmpty()) {
+            double bestDist = Double.POSITIVE_INFINITY;
+            TreeNode bestChild = null, bestParent = null;
+
+            for (var child : needsParent.values()) {
+                PointF childPos = newPos.get(child.mDisplayId);
+                float childRight = childPos.x + child.getWidth();
+                float childBottom = childPos.y + child.getHeight();
+                for (var parent : availableParents) {
+                    PointF parentPos = newPos.get(parent.mDisplayId);
+                    float parentRight = parentPos.x + parent.getWidth();
+                    float parentBottom = parentPos.y + parent.getHeight();
+
+                    // This is the smaller of the two ranges minus the amount of overlap shared
+                    // between them. The "amount of overlap" is negative if there is no overlap, but
+                    // this does not make a parenting ineligible, because we allow for attaching at
+                    // the corner and for floating point error. The overlap is more negative the
+                    // farther apart the closest corner pair is.
+                    //
+                    // For each axis, this calculates (SmallerRange - Overlap). If one range lies
+                    // completely in the other (or they are equal), the axis' deviation will be
+                    // zero.
+                    //
+                    // The "SmallerRange," which refers to smaller of the widths of the two rects,
+                    // or smaller of the heights of the two rects, is added to the deviation so that
+                    // a maximum overlap results in a deviation of zero.
+                    float xSmallerRange = Math.min(child.getWidth(), parent.getWidth());
+                    float ySmallerRange = Math.min(child.getHeight(), parent.getHeight());
+                    float xOverlap
+                            = Math.min(parentRight, childRight)
+                            - Math.max(parentPos.x, childPos.x);
+                    float yOverlap
+                            = Math.min(parentBottom, childBottom)
+                            - Math.max(parentPos.y, childPos.y);
+                    float xDeviation = xSmallerRange - xOverlap;
+                    float yDeviation = ySmallerRange - yOverlap;
+
+                    float offset;
+                    int pos;
+                    if (xDeviation <= yDeviation) {
+                        if (childPos.y < parentPos.y) {
+                            yDeviation = childBottom - parentPos.y;
+                            pos = POSITION_TOP;
+                        } else {
+                            yDeviation = parentBottom - childPos.y;
+                            pos = POSITION_BOTTOM;
+                        }
+                        offset = childPos.x - parentPos.x;
+                    } else {
+                        if (childPos.x < parentPos.x) {
+                            xDeviation = childRight - parentPos.x;
+                            pos = POSITION_LEFT;
+                        } else {
+                            xDeviation = parentRight - childPos.x;
+                            pos = POSITION_RIGHT;
+                        }
+                        offset = childPos.y - parentPos.y;
+                    }
+
+                    double dist = Math.hypot(xDeviation, yDeviation);
+                    if (dist >= bestDist) {
+                        continue;
+                    }
+
+                    bestDist = dist;
+                    bestChild = child;
+                    bestParent = parent;
+                    // Eagerly update the child's parenting info, even though we may not use it, in
+                    // which case it will be overwritten later.
+                    bestChild.mPosition = pos;
+                    bestChild.mOffset = offset;
+                }
+            }
+
+            assert bestParent != null & bestChild != null;
+
+            bestParent.addChild(bestChild);
+            if (null == needsParent.remove(bestChild.mDisplayId)) {
+                throw new IllegalStateException("child not in pending set! " + bestChild);
+            }
+            availableParents.add(bestChild);
+        }
+
+        // The conversion may have introduced an intersection of two display rects. If they are
+        // bigger than our error tolerance, this function will remove them.
+        normalize();
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -450,6 +583,20 @@
         return a == b || (Float.isNaN(a) && Float.isNaN(b)) || Math.abs(a - b) < EPSILON;
     }
 
+    private Map<Integer, TreeNode> allNodesIdMap() {
+        var pend = new ArrayDeque<TreeNode>();
+        var found = new HashMap<Integer, TreeNode>();
+
+        pend.push(mRoot);
+        do {
+            TreeNode node = pend.pop();
+            found.put(node.mDisplayId, node);
+            pend.addAll(node.mChildren);
+        } while (!pend.isEmpty());
+
+        return found;
+    }
+
     public static final class TreeNode implements Parcelable {
         public static final int POSITION_LEFT = 0;
         public static final int POSITION_TOP = 1;
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/flags.aconfig
similarity index 63%
rename from core/java/android/hardware/flags/overlayproperties_flags.aconfig
rename to core/java/android/hardware/flags/flags.aconfig
index 6c86108..5ca6c6b 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/flags.aconfig
@@ -2,6 +2,15 @@
 container: "system"
 
 flag {
+    name: "luts_api"
+    is_exported: true
+    is_fixed_read_only: true
+    namespace: "core_graphics"
+    description: "public Luts related Apis"
+    bug: "349667978"
+}
+
+flag {
     name: "overlayproperties_class_api"
     is_exported: true
     namespace: "core_graphics"
diff --git a/core/java/android/hardware/input/AidlInputGestureData.aidl b/core/java/android/hardware/input/AidlInputGestureData.aidl
index e33ec53..f7410d2 100644
--- a/core/java/android/hardware/input/AidlInputGestureData.aidl
+++ b/core/java/android/hardware/input/AidlInputGestureData.aidl
@@ -28,15 +28,18 @@
     String appLaunchPackageName;
     String appLaunchClassName;
 
+    @JavaDerive(equals=true)
     parcelable KeyTrigger {
         int keycode;
         int modifierState;
     }
 
+    @JavaDerive(equals=true)
     parcelable TouchpadGestureTrigger {
         int gestureType;
     }
 
+    @JavaDerive(equals=true)
     union Trigger {
         KeyTrigger key;
         TouchpadGestureTrigger touchpadGesture;
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 24951c4..711dc3a 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -115,12 +115,14 @@
     public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67;
     public static final int KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW = 68;
     public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
-    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70;
-    public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71;
+    public static final int KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW = 70;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW = 71;
     public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72;
     public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73;
     public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74;
     public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75;
+    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 76;
+
 
     public static final int FLAG_CANCELLED = 1;
 
@@ -205,12 +207,13 @@
             KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS,
             KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
             KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
-            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
-            KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+            KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
+            KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
             KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
             KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT,
             KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
             KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK,
+            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KeyGestureType {
@@ -557,14 +560,6 @@
                 return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
             case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
                 return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
-            case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_LEFT_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_RIGHT_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MAXIMIZE_FREEFORM_WINDOW;
-            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
-                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RESTORE_FREEFORM_WINDOW_SIZE;
             default:
                 return LOG_EVENT_UNSPECIFIED;
         }
@@ -777,10 +772,10 @@
                 return "KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW";
             case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW:
                 return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
-            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
-                return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
-            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
-                return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE";
+            case KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW";
+            case KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW";
             case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
                 return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN";
             case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
@@ -789,6 +784,8 @@
                 return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION";
             case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK:
                 return "KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK";
+            case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW:
+                return "KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW";
             default:
                 return Integer.toHexString(value);
         }
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 4b2f2c2..fee0749 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -170,4 +170,11 @@
   namespace: "input"
   description: "Adds key gestures for talkback and magnifier"
   bug: "375277034"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "can_window_override_power_gesture_api"
+  namespace: "wallet_integration"
+  description: "Adds new API in WindowManager class to check if the window can override the power key double tap behavior."
+  bug: "378736024"
+  }
\ No newline at end of file
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 494bfc9..b2c3bb8 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -34,6 +34,10 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.contexthub.ErrorCode;
+import android.hardware.contexthub.HubDiscoveryInfo;
+import android.hardware.contexthub.HubEndpoint;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IHubEndpointLifecycleCallback;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
@@ -42,6 +46,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -679,6 +684,29 @@
     }
 
     /**
+     * Find a list of endpoints that matches a specific ID.
+     *
+     * @param endpointId Statically generated ID for an endpoint.
+     * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery.
+     */
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @NonNull
+    public List<HubDiscoveryInfo> findEndpoints(long endpointId) {
+        try {
+            List<HubEndpointInfo> endpointInfos = mService.findEndpoints(endpointId);
+            List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size());
+            // Wrap with result type
+            for (HubEndpointInfo endpointInfo : endpointInfos) {
+                results.add(new HubDiscoveryInfo(endpointInfo));
+            }
+            return results;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set a callback to receive messages from the context hub
      *
      * @param callback Callback object
@@ -1010,6 +1038,55 @@
     }
 
     /**
+     * Registers an endpoint and its callback with the Context Hub Service.
+     *
+     * <p>An endpoint is registered with the Context Hub Service and published to the HAL. When the
+     * registration succeeds, the endpoint can receive notifications through the provided callback.
+     *
+     * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder}
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void registerEndpoint(@NonNull HubEndpoint hubEndpoint) {
+        hubEndpoint.register(mService);
+    }
+
+    /**
+     * Use a registered endpoint to connect to another endpoint (destination).
+     *
+     * <p>Context Hub Service will create the endpoint session and notify the registered endpoint.
+     * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback}
+     * object regarding the lifecycle events of the session
+     *
+     * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link
+     *     ContextHubManager#registerEndpoint(HubEndpoint)}.
+     * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous
+     *     endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}).
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void openSession(
+            @NonNull HubEndpoint hubEndpoint, @NonNull HubEndpointInfo destination) {
+        hubEndpoint.openSession(destination);
+    }
+
+    /**
+     * Unregisters an endpoint and its callback with the Context Hub Service.
+     *
+     * <p>An endpoint is unregistered from the HAL. The endpoint object will no longer receive
+     * notification through the provided callback.
+     *
+     * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder}. This
+     *     should match a previously registered object via {@link
+     *     ContextHubManager#registerEndpoint(HubEndpoint)}.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void unregisterEndpoint(@NonNull HubEndpoint hubEndpoint) {
+        hubEndpoint.unregister();
+    }
+
+    /**
      * Queries for the list of preloaded nanoapp IDs on the system.
      *
      * @param hubInfo The Context Hub to query a list of nanoapp IDs from.
@@ -1168,6 +1245,7 @@
         requireNonNull(mainLooper, "mainLooper cannot be null");
         mService = service;
         mMainLooper = mainLooper;
+
         try {
             mService.registerCallback(mClientCallback);
         } catch (RemoteException e) {
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index bd87b5c..ee55f81 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -51,18 +51,23 @@
 
     /**
      * Constants describing the type of a transaction through the Context Hub Service.
-     * {@hide}
+     *
+     * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "TYPE_" }, value = {
-            TYPE_LOAD_NANOAPP,
-            TYPE_UNLOAD_NANOAPP,
-            TYPE_ENABLE_NANOAPP,
-            TYPE_DISABLE_NANOAPP,
-            TYPE_QUERY_NANOAPPS,
-            TYPE_RELIABLE_MESSAGE,
-    })
-    public @interface Type { }
+    @IntDef(
+            prefix = {"TYPE_"},
+            value = {
+                TYPE_LOAD_NANOAPP,
+                TYPE_UNLOAD_NANOAPP,
+                TYPE_ENABLE_NANOAPP,
+                TYPE_DISABLE_NANOAPP,
+                TYPE_QUERY_NANOAPPS,
+                TYPE_RELIABLE_MESSAGE,
+                TYPE_HUB_MESSAGE_DEFAULT,
+                TYPE_HUB_MESSAGE_REQUIRES_RESPONSE,
+            })
+    public @interface Type {}
 
     public static final int TYPE_LOAD_NANOAPP = 0;
     public static final int TYPE_UNLOAD_NANOAPP = 1;
@@ -71,24 +76,34 @@
     public static final int TYPE_QUERY_NANOAPPS = 4;
     public static final int TYPE_RELIABLE_MESSAGE = 5;
 
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public static final int TYPE_HUB_MESSAGE_DEFAULT = 6;
+
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7;
+
     /**
      * Constants describing the result of a transaction or request through the Context Hub Service.
-     * {@hide}
+     *
+     * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "RESULT_" }, value = {
-            RESULT_SUCCESS,
-            RESULT_FAILED_UNKNOWN,
-            RESULT_FAILED_BAD_PARAMS,
-            RESULT_FAILED_UNINITIALIZED,
-            RESULT_FAILED_BUSY,
-            RESULT_FAILED_AT_HUB,
-            RESULT_FAILED_TIMEOUT,
-            RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
-            RESULT_FAILED_HAL_UNAVAILABLE,
-            RESULT_FAILED_NOT_SUPPORTED,
-    })
+    @IntDef(
+            prefix = {"RESULT_"},
+            value = {
+                RESULT_SUCCESS,
+                RESULT_FAILED_UNKNOWN,
+                RESULT_FAILED_BAD_PARAMS,
+                RESULT_FAILED_UNINITIALIZED,
+                RESULT_FAILED_BUSY,
+                RESULT_FAILED_AT_HUB,
+                RESULT_FAILED_TIMEOUT,
+                RESULT_FAILED_SERVICE_INTERNAL_FAILURE,
+                RESULT_FAILED_HAL_UNAVAILABLE,
+                RESULT_FAILED_NOT_SUPPORTED,
+            })
     public @interface Result {}
+
     public static final int RESULT_SUCCESS = 0;
     /**
      * Generic failure mode.
@@ -143,7 +158,8 @@
          */
         private R mContents;
 
-        Response(@ContextHubTransaction.Result int result, R contents) {
+        /** @hide */
+        public Response(@ContextHubTransaction.Result int result, R contents) {
             mResult = result;
             mContents = contents;
         }
@@ -206,7 +222,8 @@
      */
     private boolean mIsResponseSet = false;
 
-    ContextHubTransaction(@Type int type) {
+    /** @hide */
+    public ContextHubTransaction(@Type int type) {
         mTransactionType = type;
     }
 
@@ -338,16 +355,16 @@
     /**
      * Sets the response of the transaction.
      *
-     * This method should only be invoked by ContextHubManager as a result of a callback from
-     * the Context Hub Service indicating the response from a transaction. This method should not be
+     * <p>This method should only be invoked by ContextHubManager as a result of a callback from the
+     * Context Hub Service indicating the response from a transaction. This method should not be
      * invoked more than once.
      *
      * @param response the response to set
-     *
      * @throws IllegalStateException if this method is invoked multiple times
      * @throws NullPointerException if the response is null
+     * @hide
      */
-    /* package */ void setResponse(ContextHubTransaction.Response<T> response) {
+    public void setResponse(ContextHubTransaction.Response<T> response) {
         synchronized (this) {
             Objects.requireNonNull(response, "Response cannot be null");
             if (mIsResponseSet) {
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index b0cc763..5128723 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -18,17 +18,20 @@
 
 // Declare any non-default types here with import statements
 import android.app.PendingIntent;
-import android.hardware.location.HubInfo;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IContextHubEndpoint;
+import android.hardware.contexthub.IContextHubEndpointCallback;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
-import android.hardware.location.NanoApp;
-import android.hardware.location.NanoAppBinary;
-import android.hardware.location.NanoAppFilter;
-import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.HubInfo;
 import android.hardware.location.IContextHubCallback;
 import android.hardware.location.IContextHubClient;
 import android.hardware.location.IContextHubClientCallback;
 import android.hardware.location.IContextHubTransactionCallback;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.NanoAppInstanceInfo;
 
 /**
  * @hide
@@ -122,4 +125,12 @@
     // Enables or disables test mode
     @EnforcePermission("ACCESS_CONTEXT_HUB")
     boolean setTestMode(in boolean enable);
+
+    // Finds all endpoints that havea specific ID
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    List<HubEndpointInfo> findEndpoints(long endpointId);
+
+    // Register an endpoint with the context hub
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    IContextHubEndpoint registerEndpoint(in HubEndpointInfo pendingEndpointInfo, in IContextHubEndpointCallback callback);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8c3f0ef..dadb5c38 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -55,6 +55,7 @@
 import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_OTHER;
 import static android.view.inputmethod.ConnectionlessHandwritingCallback.CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED;
 import static android.view.inputmethod.Flags.FLAG_CONNECTIONLESS_HANDWRITING;
+import static android.view.inputmethod.Flags.FLAG_IME_SWITCHER_REVAMP_API;
 import static android.view.inputmethod.Flags.ctrlShiftShortcut;
 import static android.view.inputmethod.Flags.predictiveBackIme;
 
@@ -3436,7 +3437,7 @@
         initialize();
         mInlineSuggestionSessionController.notifyOnStartInput(
                 editorInfo == null ? null : editorInfo.packageName,
-                editorInfo == null ? null : editorInfo.autofillId);
+                editorInfo == null ? null : editorInfo.getAutofillId());
         if (DEBUG) Log.v(TAG, "CALL: onStartInput");
         onStartInput(editorInfo, restarting);
         if (mDecorViewVisible) {
@@ -4392,6 +4393,39 @@
     }
 
     /**
+     * Called when the requested visibility of a custom IME Switcher button changes.
+     *
+     * <p>When the system provides an IME navigation bar, it may decide to show an IME Switcher
+     * button inside this bar. However, the IME can request hiding the bar provided by the system
+     * with {@code getWindowInsetsController().hide(captionBar())} (the IME navigation bar provides
+     * {@link Type#captionBar() captionBar} insets to the IME window). If the request is successful,
+     * then it becomes the IME's responsibility to provide a custom IME Switcher button in its
+     * input view, with equivalent functionality.</p>
+     *
+     * <p>This custom button is only requested to be visible when the system provides the IME
+     * navigation bar, both the bar and the IME Switcher button inside it should be visible,
+     * but the IME successfully requested to hide the bar. This does not depend on the current
+     * visibility of the IME. It could be called with {@code true} while the IME is hidden, in
+     * which case the IME should prepare to show the button as soon as the IME itself is shown.</p>
+     *
+     * <p>This is only called when the requested visibility changes. The default value is
+     * {@code false} and as such, this will not be called initially if the resulting value is
+     * {@code false}.</p>
+     *
+     * <p>This can be called at any time after {@link #onCreate}, even if the IME is not currently
+     * visible. However, this is not guaranteed to be called before the IME is shown, as it depends
+     * on when the IME requested hiding the IME navigation bar. If the request is sent during
+     * the showing flow (e.g. during {@link #onStartInputView}), this will be called shortly after
+     * {@link #onWindowShown}, but before the first IME frame is drawn.</p>
+     *
+     * @param visible whether the button is requested visible or not.
+     */
+    @FlaggedApi(FLAG_IME_SWITCHER_REVAMP_API)
+    public void onCustomImeSwitcherButtonRequestedVisible(boolean visible) {
+        // Intentionally empty
+    }
+
+    /**
      * Called when the IME switch button was clicked from the client. Depending on the number of
      * enabled IME subtypes, this will either switch to the next IME/subtype, or show the input
      * method picker dialog.
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index b08454d..38be8d9 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -41,6 +41,7 @@
 import android.view.WindowInsetsController.Appearance;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
+import android.view.inputmethod.Flags;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 
@@ -178,6 +179,9 @@
 
         private boolean mDrawLegacyNavigationBarBackground;
 
+        /** Whether a custom IME Switcher button should be visible. */
+        private boolean mCustomImeSwitcherVisible;
+
         private final Rect mTempRect = new Rect();
         private final int[] mTempPos = new int[2];
 
@@ -265,6 +269,7 @@
                     // IME navigation bar.
                     boolean visible = insets.isVisible(captionBar());
                     mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
+                    checkCustomImeSwitcherVisibility();
                 }
                 return view.onApplyWindowInsets(insets);
             });
@@ -491,6 +496,8 @@
                     mShouldShowImeSwitcherWhenImeIsShown;
             mShouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherWhenImeIsShown;
 
+            checkCustomImeSwitcherVisibility();
+
             mService.mWindow.getWindow().getDecorView().getWindowInsetsController()
                     .setImeCaptionBarInsetsHeight(getImeCaptionBarHeight(imeDrawsImeNavBar));
 
@@ -616,12 +623,33 @@
                     && mNavigationBarFrame.getVisibility() == View.VISIBLE;
         }
 
+        /**
+         * Checks if a custom IME Switcher button should be visible, and notifies the IME when this
+         * state changes. This can only be {@code true} if three conditions are met:
+         *
+         * <li>The IME should draw the IME navigation bar.</li>
+         * <li>The IME Switcher button should be visible when the IME is visible.</li>
+         * <li>The IME navigation bar should be visible, but was requested hidden by the IME.</li>
+         */
+        private void checkCustomImeSwitcherVisibility() {
+            if (!Flags.imeSwitcherRevampApi()) {
+                return;
+            }
+            final boolean visible = mImeDrawsImeNavBar && mShouldShowImeSwitcherWhenImeIsShown
+                    && mNavigationBarFrame != null && !isShown();
+            if (visible != mCustomImeSwitcherVisible) {
+                mCustomImeSwitcherVisible = visible;
+                mService.onCustomImeSwitcherButtonRequestedVisible(mCustomImeSwitcherVisible);
+            }
+        }
+
         @Override
         public String toDebugString() {
             return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
                     + " mNavigationBarFrame=" + mNavigationBarFrame
                     + " mShouldShowImeSwitcherWhenImeIsShown="
                     + mShouldShowImeSwitcherWhenImeIsShown
+                    + " mCustomImeSwitcherVisible="  + mCustomImeSwitcherVisible
                     + " mAppearance=0x" + Integer.toHexString(mAppearance)
                     + " mDarkIntensity=" + mDarkIntensity
                     + " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground
diff --git a/core/java/android/net/vcn/VcnFrameworkInitializer.java b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java
similarity index 86%
rename from core/java/android/net/vcn/VcnFrameworkInitializer.java
rename to core/java/android/net/ConnectivityFrameworkInitializerBaklava.java
index 8cb213b..1f0fa92 100644
--- a/core/java/android/net/vcn/VcnFrameworkInitializer.java
+++ b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java
@@ -14,15 +14,21 @@
  * limitations under the License.
  */
 
-package android.net.vcn;
+package android.net;
 
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
+
+import android.annotation.FlaggedApi;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.app.SystemServiceRegistry;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.net.vcn.IVcnManagementService;
+import android.net.vcn.VcnManager;
 import android.os.Build;
 import android.os.SystemProperties;
 
@@ -31,8 +37,9 @@
  *
  * @hide
  */
-// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES)
-public final class VcnFrameworkInitializer {
+@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class ConnectivityFrameworkInitializerBaklava {
     /**
      * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link
      * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers
@@ -55,7 +62,7 @@
      */
     private static final int VENDOR_API_FOR_ANDROID_V = 202404;
 
-    private VcnFrameworkInitializer() {}
+    private ConnectivityFrameworkInitializerBaklava() {}
 
     // Suppressing AndroidFrameworkCompatChange because we're querying vendor
     // partition SDK level, not application's target SDK version (which BTW we
@@ -86,7 +93,10 @@
      *
      * @throws IllegalStateException if this is called anywhere besides {@link
      *     SystemServiceRegistry}.
+     * @hide
      */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static void registerServiceWrappers() {
         SystemServiceRegistry.registerContextAwareService(
                 VcnManager.VCN_MANAGEMENT_SERVICE_STRING,
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index af93c96..3219ce8 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,6 +16,7 @@
 package android.net.vcn;
 
 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
 import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
 
@@ -82,7 +83,15 @@
  * </ul>
  */
 public final class VcnGatewayConnectionConfig {
-    /** @hide */
+    /**
+     * Minimum NAT timeout not set.
+     *
+     * <p>When the timeout is not set, the device will automatically choose a keepalive interval and
+     * may reduce the keepalive frequency for power-optimization.
+     */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    // This constant does not represent a minimum value. It indicates the value is not configured.
+    @SuppressLint("MinMaxConstant")
     public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1;
 
     /** @hide */
@@ -773,7 +782,7 @@
          *
          * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
          *     Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
-         *     Gateway.
+         *     Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value.
          * @return this {@link Builder} instance, for chaining
          */
         @NonNull
@@ -781,8 +790,10 @@
                 @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
                         int minUdpPort4500NatTimeoutSeconds) {
             Preconditions.checkArgument(
-                    minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
-                    "Timeout must be at least 120s");
+                    minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+                            || minUdpPort4500NatTimeoutSeconds
+                                    >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+                    "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
 
             mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
             return this;
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
index 1fc91ee..3638429 100644
--- a/core/java/android/net/vcn/VcnTransportInfo.java
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -17,13 +17,16 @@
 package android.net.vcn;
 
 import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API;
 import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS;
 import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.net.NetworkCapabilities;
 import android.net.TransportInfo;
 import android.net.wifi.WifiInfo;
@@ -52,23 +55,29 @@
  * @hide
  */
 // TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore
-public class VcnTransportInfo implements TransportInfo, Parcelable {
+@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class VcnTransportInfo implements TransportInfo, Parcelable {
     @Nullable private final WifiInfo mWifiInfo;
     private final int mSubId;
     private final int mMinUdpPort4500NatTimeoutSeconds;
 
+    /** @hide */
     public VcnTransportInfo(@NonNull WifiInfo wifiInfo) {
         this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
     }
 
+    /** @hide */
     public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) {
         this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds);
     }
 
+    /** @hide */
     public VcnTransportInfo(int subId) {
         this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
     }
 
+    /** @hide */
     public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) {
         this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds);
     }
@@ -86,6 +95,7 @@
      * <p>If the underlying Network for the associated VCN is Cellular, returns null.
      *
      * @return the WifiInfo if there is an underlying WiFi connection, else null.
+     * @hide
      */
     @Nullable
     public WifiInfo getWifiInfo() {
@@ -100,17 +110,27 @@
      *
      * @return the Subscription ID if a cellular underlying Network is present, else {@link
      *     android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+     * @hide
      */
     public int getSubId() {
         return mSubId;
     }
 
     /**
-     * Get the VCN provided UDP port 4500 NAT timeout
+     * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping.
      *
-     * @return the UDP 4500 NAT timeout, or
+     * <p>To ensure uninterrupted connectivity, the device must send keepalive packets before the
+     * timeout. Failure to do so may result in the mapping being cleared and connection termination.
+     * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
+     * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
+     *
+     * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or
      *     VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set.
+     * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int)
+     * @hide
      */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public int getMinUdpPort4500NatTimeoutSeconds() {
         return mMinUdpPort4500NatTimeoutSeconds;
     }
@@ -129,12 +149,21 @@
                 && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @Override
     @NonNull
     public TransportInfo makeCopy(long redactions) {
@@ -149,6 +178,9 @@
                 mMinUdpPort4500NatTimeoutSeconds);
     }
 
+    /** @hide */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @Override
     public long getApplicableRedactions() {
         long redactions = REDACT_FOR_NETWORK_SETTINGS;
@@ -161,7 +193,13 @@
         return redactions;
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mSubId);
@@ -174,7 +212,13 @@
         return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }";
     }
 
-    /** Implement the Parcelable interface */
+    /**
+     * Implement the Parcelable interface
+     *
+     * @hide
+     */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final @NonNull Creator<VcnTransportInfo> CREATOR =
             new Creator<VcnTransportInfo>() {
                 public VcnTransportInfo createFromParcel(Parcel in) {
@@ -201,37 +245,63 @@
                 }
             };
 
-    /** This class can be used to construct a {@link VcnTransportInfo}. */
+    /**
+     * This class can be used to construct a {@link VcnTransportInfo}.
+     *
+     * @hide
+     */
+    @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final class Builder {
         private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
 
-        /** Construct Builder */
+        /**
+         * Construct Builder
+         *
+         * @hide
+         */
+        @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         public Builder() {}
 
         /**
-         * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout.
+         * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping.
          *
          * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs,
          * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data.
          *
-         * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN
-         *     Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN
-         *     Gateway.
+         * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway
+         *     guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET}
+         *     to clear this value. To ensure uninterrupted connectivity, the device must send
+         *     keepalive packets within this interval. Failure to do so may result in the mapping
+         *     being cleared and connection termination.
          * @return this {@link Builder} instance, for chaining
+         * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int)
+         * @hide
          */
+        @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         @NonNull
         public Builder setMinUdpPort4500NatTimeoutSeconds(
                 @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS)
                         int minUdpPort4500NatTimeoutSeconds) {
             Preconditions.checkArgument(
-                    minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
-                    "Timeout must be at least 120s");
+                    minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET
+                            || minUdpPort4500NatTimeoutSeconds
+                                    >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS,
+                    "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET");
 
             mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
             return Builder.this;
         }
 
-        /** Build a VcnTransportInfo instance */
+        /**
+         * Build a VcnTransportInfo instance
+         *
+         * @hide
+         */
+        @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API)
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         @NonNull
         public VcnTransportInfo build() {
             return new VcnTransportInfo(
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 102bdd0..c2e9260 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
 import android.sdk.Flags;
+import android.sysprop.BackportedFixesProperties;
 import android.sysprop.DeviceProperties;
 import android.sysprop.SocProperties;
 import android.sysprop.TelephonyProperties;
@@ -1612,12 +1613,25 @@
      * is not applicable on this device,
      * otherwise {@link #BACKPORTED_FIX_STATUS_UNKNOWN}.
      */
-
     @FlaggedApi(android.os.Flags.FLAG_API_FOR_BACKPORTED_FIXES)
     public static @BackportedFixStatus int getBackportedFixStatus(long id) {
-        // TODO: b/308461809 - query aliases from system prop
-        // TODO: b/372518979 - use backported fix datastore.
-        return BACKPORTED_FIX_STATUS_UNKNOWN;
+        if (id <= 0 || id > 1023) {
+            return BACKPORTED_FIX_STATUS_UNKNOWN;
+        }
+        return isBitSet(BackportedFixesProperties.alias_bitset(), (int) id)
+                ? BACKPORTED_FIX_STATUS_FIXED : BACKPORTED_FIX_STATUS_UNKNOWN;
+    }
+
+    private static boolean isBitSet(List<Long> bitsetLongArray, int bitIndex) {
+        // Because java.util.BitSet is not threadsafe do the calculations here instead.
+        if (bitIndex < 0) {
+            return false;
+        }
+        int arrayIndex = bitIndex >> 6;
+        if (bitsetLongArray.size() <= arrayIndex) {
+            return false;
+        }
+        return (bitsetLongArray.get(arrayIndex) & (1L << bitIndex)) != 0;
     }
 
     /**
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 99e7d166..05bd10b 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -18,10 +18,12 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArrayMap;
 import android.util.Size;
@@ -72,16 +74,18 @@
     /**
      * Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain
      * Binder object(s).
-     *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int STATUS_BINDERS_NOT_PRESENT = 0;
 
     /**
      * Status when the Bundle can <b>assert</b> that there are Binder object(s) in the Parcel.
-     *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int STATUS_BINDERS_PRESENT = 1;
 
     /**
@@ -94,9 +98,10 @@
      * object to the Bundle but it is not possible to assert this fact unless the Bundle is written
      * to a Parcel.
      * </p>
-     *
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int STATUS_BINDERS_UNKNOWN = 2;
 
     /** @hide */
@@ -417,6 +422,8 @@
      * Returns a status indicating whether the bundle contains any parcelled Binder objects.
      * @hide
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public @HasBinderStatus int hasBinders() {
         if ((mFlags & FLAG_HAS_BINDERS_KNOWN) != 0) {
             if ((mFlags & FLAG_HAS_BINDERS) != 0) {
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 7529ab9..036ccd8 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -19,6 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
+import android.app.Instrumentation;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Process;
 import android.os.UserHandle;
@@ -31,7 +33,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import dalvik.annotation.optimization.NeverCompile;
-import dalvik.system.VMDebug;
 
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -111,11 +112,39 @@
     private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
 
     MessageQueue(boolean quitAllowed) {
-        mUseConcurrent = UserHandle.isCore(Process.myUid()) && !VMDebug.isDebuggingEnabled();
+        // Concurrent mode modifies behavior that is observable via reflection and is commonly used
+        // by tests.
+        // For now, we limit it to system processes to avoid breaking apps and their tests.
+        mUseConcurrent = UserHandle.isCore(Process.myUid());
+        // Even then, we don't use it if instrumentation is loaded as it breaks some
+        // platform tests.
+        final Instrumentation instrumentation = getInstrumentation();
+        mUseConcurrent &= instrumentation == null || !instrumentation.isInstrumenting();
+        // We can lift this restriction in the future after we've made it possible for test authors
+        // to test Looper and MessageQueue without resorting to reflection.
+
+        // Holdback study.
+        if (mUseConcurrent && Flags.messageQueueForceLegacy()) {
+            mUseConcurrent = false;
+        }
+
         mQuitAllowed = quitAllowed;
         mPtr = nativeInit();
     }
 
+    @android.ravenwood.annotation.RavenwoodReplace(blockedBy = ActivityThread.class)
+    private static Instrumentation getInstrumentation() {
+        final ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            return activityThread.getInstrumentation();
+        }
+        return null;
+    }
+
+    private static Instrumentation getInstrumentation$ravenwood() {
+        return null; // Instrumentation not supported on Ravenwood yet.
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java
new file mode 100644
index 0000000..f0d4f7d
--- /dev/null
+++ b/core/java/android/os/CpuHeadroomParams.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.os.health.SystemHealthManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}.
+ */
+@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS)
+public final class CpuHeadroomParams {
+    final CpuHeadroomParamsInternal mInternal;
+
+    public CpuHeadroomParams() {
+        mInternal = new CpuHeadroomParamsInternal();
+    }
+
+    /** @hide */
+    @IntDef(flag = false, prefix = {"CPU_HEADROOM_CALCULATION_TYPE_"}, value = {
+            CPU_HEADROOM_CALCULATION_TYPE_MIN, // 0
+            CPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CpuHeadroomCalculationType {
+    }
+
+    /**
+     * Calculates the headroom based on minimum value over a device-defined window.
+     */
+    public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0;
+
+    /**
+     * Calculates the headroom based on average value over a device-defined window.
+     */
+    public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
+
+    /**
+     * Sets the headroom calculation type.
+     * <p>
+     *
+     * @throws IllegalArgumentException if the type is invalid.
+     */
+    public void setCalculationType(@CpuHeadroomCalculationType int calculationType) {
+        switch (calculationType) {
+            case CPU_HEADROOM_CALCULATION_TYPE_MIN:
+            case CPU_HEADROOM_CALCULATION_TYPE_AVERAGE:
+                mInternal.calculationType = (byte) calculationType;
+                return;
+        }
+        throw new IllegalArgumentException("Invalid calculation type: " + calculationType);
+    }
+
+    /**
+     * Gets the headroom calculation type.
+     * Default to {@link #CPU_HEADROOM_CALCULATION_TYPE_MIN} if not set.
+     */
+    public @CpuHeadroomCalculationType int getCalculationType() {
+        @CpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) {
+            case CPU_HEADROOM_CALCULATION_TYPE_MIN, CPU_HEADROOM_CALCULATION_TYPE_AVERAGE ->
+                    mInternal.calculationType;
+            default -> CPU_HEADROOM_CALCULATION_TYPE_MIN;
+        };
+        return validatedType;
+    }
+
+    /**
+     * @hide
+     */
+    public CpuHeadroomParamsInternal getInternal() {
+        return mInternal;
+    }
+}
diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl
new file mode 100644
index 0000000..6cc4699
--- /dev/null
+++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.hardware.power.CpuHeadroomParams;
+
+/**
+ * Changes should be synced with match function of HintManagerService#CpuHeadroomCacheItem.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+parcelable CpuHeadroomParamsInternal {
+    boolean usesDeviceHeadroom = false;
+    CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN;
+    CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL;
+}
+
diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java
new file mode 100644
index 0000000..efb2a28
--- /dev/null
+++ b/core/java/android/os/GpuHeadroomParams.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.os.health.SystemHealthManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Headroom request params used by {@link SystemHealthManager#getGpuHeadroom(GpuHeadroomParams)}.
+ */
+@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS)
+public final class GpuHeadroomParams {
+    final GpuHeadroomParamsInternal mInternal;
+
+    public GpuHeadroomParams() {
+        mInternal = new GpuHeadroomParamsInternal();
+    }
+
+    /** @hide */
+    @IntDef(flag = false, prefix = {"GPU_HEADROOM_CALCULATION_TYPE_"}, value = {
+            GPU_HEADROOM_CALCULATION_TYPE_MIN, // 0
+            GPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface GpuHeadroomCalculationType {
+    }
+
+    /**
+     * Calculates the headroom based on minimum value over a device-defined window.
+     */
+    public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0;
+
+    /**
+     * Calculates the headroom based on average value over a device-defined window.
+     */
+    public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1;
+
+    /**
+     * Sets the headroom calculation type.
+     * <p>
+     *
+     * @throws IllegalArgumentException if the type is invalid.
+     */
+    public void setCalculationType(@GpuHeadroomCalculationType int calculationType) {
+        switch (calculationType) {
+            case GPU_HEADROOM_CALCULATION_TYPE_MIN:
+            case GPU_HEADROOM_CALCULATION_TYPE_AVERAGE:
+                mInternal.calculationType = (byte) calculationType;
+                return;
+        }
+        throw new IllegalArgumentException("Invalid calculation type: " + calculationType);
+    }
+
+    /**
+     * Gets the headroom calculation type.
+     * Default to {@link #GPU_HEADROOM_CALCULATION_TYPE_MIN} if not set.
+     */
+    public @GpuHeadroomCalculationType int getCalculationType() {
+        @GpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) {
+            case GPU_HEADROOM_CALCULATION_TYPE_MIN, GPU_HEADROOM_CALCULATION_TYPE_AVERAGE ->
+                    mInternal.calculationType;
+            default -> GPU_HEADROOM_CALCULATION_TYPE_MIN;
+        };
+        return validatedType;
+    }
+
+    /**
+     * @hide
+     */
+    public GpuHeadroomParamsInternal getInternal() {
+        return mInternal;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/core/java/android/os/GpuHeadroomParamsInternal.aidl
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to core/java/android/os/GpuHeadroomParamsInternal.aidl
index e4ccc2c..20309e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.os;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import android.hardware.power.GpuHeadroomParams;
+
+/**
+ * Changes should be synced with match function of HintManagerService#GpuHeadroomCacheItem.
+ * {@hide}
+ */
+@JavaDerive(equals = true, toString = true)
+parcelable GpuHeadroomParamsInternal {
+    GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN;
+}
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 73cdd56..3312055 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -17,6 +17,8 @@
 
 package android.os;
 
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
 import android.os.IHintSession;
 import android.hardware.power.ChannelConfig;
 import android.hardware.power.SessionConfig;
@@ -50,4 +52,8 @@
      */
     @nullable ChannelConfig getSessionChannel(in IBinder token);
     oneway void closeSessionChannel();
+    float[] getCpuHeadroom(in CpuHeadroomParamsInternal params);
+    long getCpuHeadroomMinIntervalMillis();
+    float getGpuHeadroom(in GpuHeadroomParamsInternal params);
+    long getGpuHeadroomMinIntervalMillis();
 }
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 590ddb4..e63b664 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -78,6 +78,9 @@
 # PermissionEnforcer
 per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com
 
+# RemoteCallbackList
+per-file RemoteCallbackList.java = shayba@google.com
+
 # ART
 per-file ArtModuleServiceManager.java = file:platform/art:/OWNERS
 
@@ -125,3 +128,6 @@
 
 # Dropbox
 per-file DropBoxManager* = mwachens@google.com
+
+# Flags
+per-file flags.aconfig = file:/FF_LEADS_OWNERS
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f728552..bf7116d 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1371,7 +1371,6 @@
         writeInt(N);
         if (DEBUG_ARRAY_MAP) {
             RuntimeException here =  new RuntimeException("here");
-            here.fillInStackTrace();
             Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
         }
         int startPos;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 4bc8fe0..5a53bc15 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3928,9 +3928,9 @@
 
         final int callingUid = Binder.getCallingUid();
         final int processUid = Process.myUid();
-        if (Build.isDebuggable() && callingUid != processUid) {
-            Log.w(TAG, "Uid " + processUid + " is fetching a copy of UserProperties on"
-                            + " behalf of callingUid " + callingUid + ". Possibly"
+        if (processUid == Process.SYSTEM_UID && callingUid != processUid) {
+            Log.w(TAG, "The System (uid " + processUid + ") is fetching a copy of"
+                            + " UserProperties on behalf of callingUid " + callingUid + ". Possibly"
                             + " it should carefully first clearCallingIdentity or perhaps use"
                             + " UserManagerInternal.getUserProperties() instead?",
                     new Throwable());
@@ -5308,7 +5308,13 @@
             Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS,
             Manifest.permission.QUERY_USERS}, conditional = true)
+    @CachedProperty(api = "user_manager_user_data")
     public List<UserInfo> getProfiles(@UserIdInt int userId) {
+        if (android.multiuser.Flags.cacheProfilesReadOnly()) {
+            return UserManagerCache.getProfiles(
+                    (Integer userIdentifier) -> mService.getProfiles(userIdentifier, false),
+                    userId);
+        }
         try {
             return mService.getProfiles(userId, false /* enabledOnly */);
         } catch (RemoteException re) {
@@ -6484,6 +6490,19 @@
     }
 
     /**
+     * This method is used to invalidate caches, when UserManagerService.mUsers
+     * {@link UserManagerService.UserData} is modified, including changes to {@link UserInfo}.
+     * In practice we determine modification by when that data is persisted, or scheduled to be
+     * presisted, to xml.
+     * @hide
+     */
+    public static final void invalidateCacheOnUserDataChanged() {
+        if (android.multiuser.Flags.cacheProfilesReadOnly()) {
+            UserManagerCache.invalidateProfiles();
+        }
+    }
+
+    /**
      * Returns a serial number on this device for a given userId. User handles can be recycled
      * when deleting and creating users, but serial numbers are not reused until the device is
      * wiped.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0cffd9f..f6bc389 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -41,6 +41,7 @@
 import android.os.vibrator.RampSegment;
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationEffectSegment;
+import android.os.vibrator.VibratorEnvelopeEffectInfo;
 import android.os.vibrator.VibratorFrequencyProfileLegacy;
 import android.util.MathUtils;
 
@@ -1483,6 +1484,15 @@
         public @interface PrimitiveType {
         }
 
+        /** @hide */
+        @IntDef(prefix = { "DELAY_TYPE_" }, value = {
+                DELAY_TYPE_PAUSE,
+                DELAY_TYPE_RELATIVE_START_OFFSET,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface DelayType {
+        }
+
         /**
          * Exception thrown when adding an element to a {@link Composition} that already ends in an
          * indefinitely repeating effect.
@@ -1541,6 +1551,53 @@
         // Internally this maps to the HAL constant CompositePrimitive::LOW_TICK
         public static final int PRIMITIVE_LOW_TICK = 8;
 
+        /**
+         * The delay represents a pause in the composition between the end of the previous primitive
+         * and the beginning of the next one.
+         *
+         * <p>The primitive will start after the requested pause after the last primitive ended.
+         * The actual time the primitive will be played depends on the previous primitive's actual
+         * duration on the device hardware. This enables the combination of primitives to create
+         * more complex effects based on how close to each other they'll play. Here is an example:
+         *
+         * <pre>
+         *     VibrationEffect popEffect = VibrationEffect.startComposition()
+         *         .addPrimitive(PRIMITIVE_QUICK_RISE)
+         *         .addPrimitive(PRIMITIVE_CLICK, 0.7, 50, DELAY_TYPE_PAUSE)
+         *         .compose()
+         * </pre>
+         */
+        @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+        public static final int DELAY_TYPE_PAUSE = 0;
+
+        /**
+         * The delay represents an offset before starting this primitive, relative to the start
+         * time of the previous primitive in the composition.
+         *
+         * <p>The primitive will start at the requested fixed time after the last primitive started,
+         * independently of that primitive's actual duration on the device hardware. This enables
+         * precise timings of primitives within a composition, ensuring they'll be played at the
+         * desired intervals. Here is an example:
+         *
+         * <pre>
+         *     VibrationEffect.startComposition()
+         *         .addPrimitive(PRIMITIVE_CLICK, 1.0)
+         *         .addPrimitive(PRIMITIVE_TICK, 1.0, 20, DELAY_TYPE_RELATIVE_START_OFFSET)
+         *         .addPrimitive(PRIMITIVE_THUD, 1.0, 80, DELAY_TYPE_RELATIVE_START_OFFSET)
+         *         .compose()
+         * </pre>
+         *
+         * Will be performed on the device as follows:
+         *
+         * <pre>
+         *  0ms               20ms                     100ms
+         *  PRIMITIVE_CLICK---PRIMITIVE_TICK-----------PRIMITIVE_THUD
+         * </pre>
+         *
+         * <p>A primitive will be dropped from the composition if it overlaps with previous ones.
+         */
+        @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+        public static final int DELAY_TYPE_RELATIVE_START_OFFSET = 1;
 
         private final ArrayList<VibrationEffectSegment> mSegments = new ArrayList<>();
         private int mRepeatIndex = -1;
@@ -1665,7 +1722,26 @@
         @NonNull
         public Composition addPrimitive(@PrimitiveType int primitiveId,
                 @FloatRange(from = 0f, to = 1f) float scale, @IntRange(from = 0) int delay) {
-            PrimitiveSegment primitive = new PrimitiveSegment(primitiveId, scale, delay);
+            return addPrimitive(primitiveId, scale, delay, PrimitiveSegment.DEFAULT_DELAY_TYPE);
+        }
+
+        /**
+         * Add a haptic primitive to the end of the current composition.
+         *
+         * @param primitiveId The primitive to add
+         * @param scale The scale to apply to the intensity of the primitive.
+         * @param delay The amount of time in milliseconds to wait before playing this primitive,
+         *              as defined by the given {@code delayType}.
+         * @param delayType The type of delay to be applied, e.g. a pause between last primitive and
+         *                  this one or a start offset.
+         * @return This {@link Composition} object to enable adding multiple elements in one chain.
+         */
+        @FlaggedApi(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+        @NonNull
+        public Composition addPrimitive(@PrimitiveType int primitiveId,
+                @FloatRange(from = 0f, to = 1f) float scale, @IntRange(from = 0) int delay,
+                @DelayType int delayType) {
+            PrimitiveSegment primitive = new PrimitiveSegment(primitiveId, scale, delay, delayType);
             primitive.validate();
             return addSegment(primitive);
         }
@@ -1733,52 +1809,20 @@
                 default -> Integer.toString(id);
             };
         }
-    }
 
-    /**
-     * Start building a waveform vibration.
-     *
-     * <p>The waveform envelope builder offers more flexibility for creating waveform effects,
-     * allowing control over vibration amplitude and frequency via smooth transitions between
-     * values. The waveform will start the first transition from the vibrator off state, using
-     * the same frequency of the first control point. To provide a different initial vibration
-     * frequency, use {@link #startWaveformEnvelope(float)}.
-     *
-     * <p>Note: To check whether waveform envelope effects are supported, use
-     * {@link Vibrator#areEnvelopeEffectsSupported()}.
-     *
-     * @see VibrationEffect.WaveformEnvelopeBuilder
-     */
-    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    @NonNull
-    public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope() {
-        return new WaveformEnvelopeBuilder();
-    }
-
-    /**
-     * Start building a waveform vibration with an initial frequency.
-     *
-     * <p>The waveform envelope builder offers more flexibility for creating waveform effects,
-     * allowing control over vibration amplitude and frequency via smooth transitions between
-     * values.
-     *
-     * <p>This is the same as {@link #startWaveformEnvelope()}, but the waveform will start
-     * vibrating at given frequency, in hertz, while it transitions to the new amplitude and
-     * frequency of the first control point.
-     *
-     * <p>Note: To check whether waveform envelope effects are supported, use
-     * {@link Vibrator#areEnvelopeEffectsSupported()}.
-     *
-     * @param initialFrequencyHz The starting frequency of the vibration, in hertz. Must be greater
-     *                           than zero.
-     *
-     * @see VibrationEffect.WaveformEnvelopeBuilder
-     */
-    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    @NonNull
-    public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(
-            @FloatRange(from = 0) float initialFrequencyHz) {
-        return new WaveformEnvelopeBuilder(initialFrequencyHz);
+        /**
+         * Convert the delay type to a human readable string for debugging.
+         * @param type The delay type to convert
+         * @return The delay type in a human readable format.
+         * @hide
+         */
+        public static String delayTypeToString(@DelayType int type) {
+            return switch (type) {
+                case DELAY_TYPE_PAUSE -> "PAUSE";
+                case DELAY_TYPE_RELATIVE_START_OFFSET -> "START_OFFSET";
+                default -> Integer.toString(type);
+            };
+        }
     }
 
     /**
@@ -1792,7 +1836,7 @@
      * 100ms, holds that state for 200ms, and then ramps back down over 100ms:
      *
      * <pre>{@code
-     * VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
+     * VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
      *     .addControlPoint(1.0f, 120f, 100)
      *     .addControlPoint(1.0f, 120f, 200)
      *     .addControlPoint(0.0f, 120f, 100)
@@ -1819,27 +1863,55 @@
      *
      * <p>You can use the following APIs to obtain these limits:
      * <ul>
-     * <li>Maximum envelope control points: {@link Vibrator#getMaxEnvelopeEffectSize()}</li>
+     * <li>Maximum envelope control points: {@link VibratorEnvelopeEffectInfo#getMaxSize()}
      * <li>Minimum control point duration:
-     * {@link Vibrator#getMinEnvelopeEffectControlPointDurationMillis()}</li>
+     * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}
      * <li>Maximum control point duration:
-     * {@link Vibrator#getMaxEnvelopeEffectControlPointDurationMillis()}</li>
-     * <li>Maximum total effect duration: {@link Vibrator#getMaxEnvelopeEffectDurationMillis()}</li>
+     * {@link VibratorEnvelopeEffectInfo#getMaxControlPointDurationMillis()}
+     * <li>Maximum total effect duration: {@link VibratorEnvelopeEffectInfo#getMaxDurationMillis()}
      * </ul>
-     *
-     * @see VibrationEffect#startWaveformEnvelope()
      */
     @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public static final class WaveformEnvelopeBuilder {
 
         private ArrayList<PwleSegment> mSegments = new ArrayList<>();
         private float mLastAmplitude = 0f;
-        private float mLastFrequencyHz = 0f;
+        private float mLastFrequencyHz = Float.NaN;
 
-        private WaveformEnvelopeBuilder() {}
+        public WaveformEnvelopeBuilder() {}
 
-        private WaveformEnvelopeBuilder(float initialFrequency) {
-            mLastFrequencyHz = initialFrequency;
+        /**
+         * Sets the initial frequency for the waveform in Hertz.
+         *
+         * <p>The effect will start vibrating at this frequency when it transitions to the
+         * amplitude and frequency defined by the first control point.
+         *
+         * <p>The frequency must be greater than zero and within the supported range. To determine
+         * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating
+         * effects using frequencies outside this range will result in the vibration not playing.
+         *
+         * @param initialFrequencyHz The starting frequency of the vibration, in Hz. Must be
+         *                           greater than zero.
+         */
+        @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+        @SuppressWarnings("MissingGetterMatchingBuilder")// No getter to initial frequency once set.
+        @NonNull
+        public WaveformEnvelopeBuilder setInitialFrequencyHz(
+                @FloatRange(from = 0) float initialFrequencyHz) {
+
+            if (mSegments.isEmpty()) {
+                mLastFrequencyHz = initialFrequencyHz;
+            } else {
+                PwleSegment firstSegment = mSegments.getFirst();
+                mSegments.set(0, new PwleSegment(
+                        firstSegment.getStartAmplitude(),
+                        firstSegment.getEndAmplitude(),
+                        initialFrequencyHz, // Update start frequency
+                        firstSegment.getEndFrequencyHz(),
+                        (int) firstSegment.getDuration()));
+            }
+
+            return this;
         }
 
         /**
@@ -1850,15 +1922,13 @@
          * perceived intensity. It's determined by the actuator response curve.
          *
          * <p>Frequency must be greater than zero and within the supported range. To determine
-         * the supported range, use {@link Vibrator#getFrequencyProfile()}. This method returns a
-         * {@link android.os.vibrator.VibratorFrequencyProfile} object, which contains the
-         * minimum and maximum frequencies, among other frequency-related information. Creating
+         * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating
          * effects using frequencies outside this range will result in the vibration not playing.
          *
          * <p>Time specifies the duration (in milliseconds) for the vibrator to smoothly transition
          * from the previous control point to this new one. It must be greater than zero. To
          * transition as quickly as possible, use
-         * {@link Vibrator#getMinEnvelopeEffectControlPointDurationMillis()}.
+         * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}.
          *
          * @param amplitude   The amplitude value between 0 and 1, inclusive. 0 represents the
          *                    vibrator being off, and 1 represents the maximum achievable amplitude
@@ -1873,7 +1943,7 @@
                 @FloatRange(from = 0, to = 1) float amplitude,
                 @FloatRange(from = 0) float frequencyHz, int timeMillis) {
 
-            if (mLastFrequencyHz == 0) {
+            if (Float.isNaN(mLastFrequencyHz)) {
                 mLastFrequencyHz = frequencyHz;
             }
 
@@ -1894,6 +1964,7 @@
          * calling this method again.
          *
          * @return The {@link VibrationEffect} resulting from the list of control points.
+         * @throws IllegalStateException if no control points were added to the builder.
          */
         @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
         @NonNull
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 53f8a92..8620914 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -35,6 +35,7 @@
 import android.os.vibrator.Flags;
 import android.os.vibrator.VendorVibrationSession;
 import android.os.vibrator.VibrationConfig;
+import android.os.vibrator.VibratorEnvelopeEffectInfo;
 import android.os.vibrator.VibratorFrequencyProfile;
 import android.os.vibrator.VibratorFrequencyProfileLegacy;
 import android.util.Log;
@@ -137,6 +138,9 @@
     @Nullable
     private volatile VibrationConfig mVibrationConfig;
 
+    private VibratorFrequencyProfile mVibratorFrequencyProfile;
+    private VibratorEnvelopeEffectInfo mVibratorEnvelopeEffectInfo;
+
     /**
      * @hide to prevent subclassing from outside of the framework
      */
@@ -351,7 +355,11 @@
             return null;
         }
 
-        return new VibratorFrequencyProfile(frequencyProfile);
+        if (mVibratorFrequencyProfile == null) {
+            mVibratorFrequencyProfile = new VibratorFrequencyProfile(frequencyProfile);
+        }
+
+        return mVibratorFrequencyProfile;
     }
 
     /**
@@ -383,70 +391,28 @@
     }
 
     /**
-     * Retrieves the maximum duration supported for an envelope effect, in milliseconds.
+     * Retrieves the vibrator's capabilities and limitations for envelope effects.
      *
-     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
-     * this value will be positive. Devices with envelope effects capabilities guarantees a
-     * maximum duration equivalent to the product of {@link #getMaxEnvelopeEffectSize()} and
-     * {@link #getMaxEnvelopeEffectControlPointDurationMillis()}. If the device does not support
-     * envelope effects, this method will return 0.
+     * <p>These parameters can be used with {@link VibrationEffect.WaveformEnvelopeBuilder}
+     * to create custom envelope effects.
      *
-     * @return The maximum duration (in milliseconds) allowed for an envelope effect, or 0 if
-     * envelope effects are not supported.
+     * @return The vibrator's envelope effect information, or null if not supported. If this
+     * vibrator is a composite of multiple physical devices then this will return a profile
+     * supported in all devices, or null if the intersection is empty or not available.
+     *
+     * @see VibrationEffect.WaveformEnvelopeBuilder
      */
     @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    public int getMaxEnvelopeEffectDurationMillis() {
-        return getInfo().getMaxEnvelopeEffectDurationMillis();
-    }
+    @NonNull
+    public VibratorEnvelopeEffectInfo getEnvelopeEffectInfo() {
+        if (mVibratorEnvelopeEffectInfo == null) {
+            mVibratorEnvelopeEffectInfo = new VibratorEnvelopeEffectInfo(
+                    getInfo().getMaxEnvelopeEffectSize(),
+                    getInfo().getMinEnvelopeEffectControlPointDurationMillis(),
+                    getInfo().getMaxEnvelopeEffectControlPointDurationMillis());
+        }
 
-    /**
-     * Retrieves the maximum number of control points supported for an envelope effect.
-     *
-     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
-     * this value will be positive. Devices with envelope effects capabilities guarantee support
-     * for a minimum of 16 control points. If the device does not support envelope effects,
-     * this method will return 0.
-     *
-     * @return the maximum number of control points allowed for an envelope effect, or 0 if
-     * envelope effects are not supported.
-     */
-    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    public int getMaxEnvelopeEffectSize() {
-        return getInfo().getMaxEnvelopeEffectSize();
-    }
-
-    /**
-     * Retrieves the minimum duration supported between two control points within an envelope
-     * effect, in milliseconds.
-     *
-     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
-     * this value will be positive. Devices with envelope effects capabilities guarantee
-     * support for durations down to at least 20 milliseconds. If the device does
-     * not support envelope effects, this method will return 0.
-     *
-     * @return the minimum allowed duration between two control points in an envelope effect,
-     * or 0 if envelope effects are not supported.
-     */
-    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    public int getMinEnvelopeEffectControlPointDurationMillis() {
-        return getInfo().getMinEnvelopeEffectControlPointDurationMillis();
-    }
-
-    /**
-     * Retrieves the maximum duration supported between two control points within an envelope
-     * effect, in milliseconds.
-     *
-     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
-     * this value will be positive. Devices with envelope effects capabilities guarantee support
-     * for durations up to at least 1 second. If the device does not support envelope effects,
-     * this method will return 0.
-     *
-     * @return the maximum allowed duration between two control points in an envelope effect,
-     * or 0 if envelope effects are not supported.
-     */
-    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    public int getMaxEnvelopeEffectControlPointDurationMillis() {
-        return getInfo().getMaxEnvelopeEffectControlPointDurationMillis();
+        return mVibratorEnvelopeEffectInfo;
     }
 
     /**
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 9dec867..84325a4 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -121,7 +121,7 @@
      * @param qFactor                  The vibrator quality factor.
      * @param frequencyProfileLegacy   The description of the vibrator supported frequencies and max
      *                                 amplitude mappings.
-     * @param frequencyProfile       The description of the vibrator supported frequencies and
+     * @param frequencyProfile         The description of the vibrator supported frequencies and
      *                                 output acceleration mappings.
      * @param maxEnvelopeEffectSize    The maximum number of control points supported for an
      *                                 envelope effect.
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index d9db28e..9b1bf05 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -4,6 +4,15 @@
 
 # keep-sorted start block=yes newline_separated=yes
 flag {
+     # Holdback study for concurrent MessageQueue.
+     # Do not promote beyond trunkfood.
+     namespace: "system_performance"
+     name: "message_queue_force_legacy"
+     description: "Whether to holdback concurrent MessageQueue (force legacy)."
+     bug: "336880969"
+}
+
+flag {
     name: "adpf_gpu_report_actual_work_duration"
     is_exported: true
     namespace: "game"
@@ -66,6 +75,14 @@
 }
 
 flag {
+    name: "adpf_use_load_hints"
+    namespace: "game"
+    description: "Guards use of the ADPF public load hints behind a readonly flag"
+    is_fixed_read_only: true
+    bug: "367803904"
+}
+
+flag {
     name: "allow_consentless_bugreport_delegated_consent"
     namespace: "crumpet"
     description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
@@ -148,6 +165,13 @@
 }
 
 flag {
+    name: "cpu_gpu_headrooms"
+    namespace: "game"
+    description: "Feature flag for adding CPU/GPU headroom API"
+    bug: "346604998"
+}
+
+flag {
     name: "disallow_cellular_null_ciphers_restriction"
     namespace: "cellular_security"
     description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices."
@@ -179,6 +203,17 @@
 }
 
 flag {
+    name: "material_colors_10_2024"
+    namespace: "systemui"
+    description: "Adding new Material Tokens as of October 2024"
+    bug: "376195115"
+    is_exported: true
+    metadata {
+        purpose: PURPOSE_FEATURE
+    }
+}
+
+flag {
     name: "message_queue_tail_tracking"
     namespace: "system_performance"
     description: "track tail of message queue."
@@ -253,6 +288,15 @@
 
 flag {
      namespace: "system_performance"
+     name: "enable_has_binders"
+     is_exported: true
+     description: "Add hasBinders to Public API under a flag."
+     is_fixed_read_only: true
+     bug: "330345513"
+}
+
+flag {
+     namespace: "system_performance"
      name: "perfetto_sdk_tracing"
      description: "Tracing using Perfetto SDK."
      bug: "303199244"
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index deabfed..4db9bc3 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -17,6 +17,7 @@
 package android.os.health;
 
 import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
@@ -25,6 +26,11 @@
 import android.os.BatteryStats;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CpuHeadroomParams;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParams;
+import android.os.GpuHeadroomParamsInternal;
+import android.os.IHintManager;
 import android.os.IPowerStatsService;
 import android.os.OutcomeReceiver;
 import android.os.PowerMonitor;
@@ -68,6 +74,8 @@
     private final IBatteryStats mBatteryStats;
     @Nullable
     private final IPowerStatsService mPowerStats;
+    @Nullable
+    private final IHintManager mHintManager;
     private List<PowerMonitor> mPowerMonitorsInfo;
     private final Object mPowerMonitorsLock = new Object();
     private static final long TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS = 10_000;
@@ -88,14 +96,111 @@
     public SystemHealthManager() {
         this(IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME)),
                 IPowerStatsService.Stub.asInterface(
-                        ServiceManager.getService(Context.POWER_STATS_SERVICE)));
+                        ServiceManager.getService(Context.POWER_STATS_SERVICE)),
+                IHintManager.Stub.asInterface(
+                        ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE)));
     }
 
     /** {@hide} */
     public SystemHealthManager(@NonNull IBatteryStats batteryStats,
-            @Nullable IPowerStatsService powerStats) {
+            @Nullable IPowerStatsService powerStats, @Nullable IHintManager hintManager) {
         mBatteryStats = batteryStats;
         mPowerStats = powerStats;
+        mHintManager = hintManager;
+    }
+
+    /**
+     * Provides an estimate of global available CPU headroom of the calling thread.
+     * <p>
+     *
+     * @param  params params to customize the CPU headroom calculation, null to use default params.
+     * @return a single value a {@code Float.NaN} if it's temporarily unavailable.
+     *         A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be
+     *         granted.
+     * @throws UnsupportedOperationException if the API is unsupported or the request params can't
+     *         be served.
+     */
+    @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+    public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom(
+            @Nullable CpuHeadroomParams params) {
+        if (mHintManager == null) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mHintManager.getCpuHeadroom(
+                    params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0];
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+
+
+    /**
+     * Provides an estimate of global available GPU headroom of the device.
+     * <p>
+     *
+     * @param  params params to customize the GPU headroom calculation, null to use default params.
+     * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable.
+     *         A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be
+     *         granted.
+     * @throws UnsupportedOperationException if the API is unsupported or the request params can't
+     *         be served.
+     */
+    @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+    public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom(
+            @Nullable GpuHeadroomParams params) {
+        if (mHintManager == null) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mHintManager.getGpuHeadroom(
+                    params != null ? params.getInternal() : new GpuHeadroomParamsInternal());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Minimum polling interval for calling {@link #getCpuHeadroom(CpuHeadroomParams)} in
+     * milliseconds.
+     * <p>
+     * The {@link #getCpuHeadroom(CpuHeadroomParams)} API may return cached result if called more
+     * frequent than the interval.
+     *
+     * @throws UnsupportedOperationException if the API is unsupported.
+     */
+    @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+    public long getCpuHeadroomMinIntervalMillis() {
+        if (mHintManager == null) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mHintManager.getCpuHeadroomMinIntervalMillis();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Minimum polling interval for calling {@link #getGpuHeadroom(GpuHeadroomParams)} in
+     * milliseconds.
+     * <p>
+     * The {@link #getGpuHeadroom(GpuHeadroomParams)} API may return cached result if called more
+     * frequent than the interval.
+     *
+     * @throws UnsupportedOperationException if the API is unsupported.
+     */
+    @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS)
+    public long getGpuHeadroomMinIntervalMillis() {
+        if (mHintManager == null) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mHintManager.getGpuHeadroomMinIntervalMillis();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -261,7 +366,7 @@
                         mPowerMonitorsInfo = result;
                     }
                     if (executor != null) {
-                        executor.execute(()-> onResult.accept(result));
+                        executor.execute(() -> onResult.accept(result));
                     } else {
                         onResult.accept(result);
                     }
diff --git a/core/java/android/os/vibrator/PrimitiveSegment.java b/core/java/android/os/vibrator/PrimitiveSegment.java
index 91653ed..889d735 100644
--- a/core/java/android/os/vibrator/PrimitiveSegment.java
+++ b/core/java/android/os/vibrator/PrimitiveSegment.java
@@ -26,6 +26,7 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Locale;
 import java.util.Objects;
 
 /**
@@ -43,19 +44,29 @@
     /** @hide */
     public static final int DEFAULT_DELAY_MILLIS = 0;
 
+    /** @hide */
+    public static final int DEFAULT_DELAY_TYPE = VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+
     private final int mPrimitiveId;
     private final float mScale;
     private final int mDelay;
+    private final int mDelayType;
 
     PrimitiveSegment(@NonNull Parcel in) {
-        this(in.readInt(), in.readFloat(), in.readInt());
+        this(in.readInt(), in.readFloat(), in.readInt(), in.readInt());
     }
 
     /** @hide */
     public PrimitiveSegment(int id, float scale, int delay) {
+        this(id, scale, delay, DEFAULT_DELAY_TYPE);
+    }
+
+    /** @hide */
+    public PrimitiveSegment(int id, float scale, int delay, int delayType) {
         mPrimitiveId = id;
         mScale = scale;
         mDelay = delay;
+        mDelayType = delayType;
     }
 
     public int getPrimitiveId() {
@@ -70,6 +81,11 @@
         return mDelay;
     }
 
+    /** @hide */
+    public int getDelayType() {
+        return mDelayType;
+    }
+
     @Override
     public long getDuration() {
         return -1;
@@ -112,8 +128,7 @@
         if (Float.compare(mScale, newScale) == 0) {
             return this;
         }
-
-        return new PrimitiveSegment(mPrimitiveId, newScale, mDelay);
+        return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
     }
 
     /** @hide */
@@ -124,8 +139,7 @@
         if (Float.compare(mScale, newScale) == 0) {
             return this;
         }
-
-        return new PrimitiveSegment(mPrimitiveId, newScale, mDelay);
+        return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
     }
 
     /** @hide */
@@ -142,6 +156,7 @@
                 VibrationEffect.Composition.PRIMITIVE_LOW_TICK, "primitiveId");
         Preconditions.checkArgumentInRange(mScale, 0f, 1f, "scale");
         VibrationEffectSegment.checkDurationArgument(mDelay, "delay");
+        Preconditions.checkArgument(isValidDelayType(mDelayType), "delayType");
     }
 
     @Override
@@ -150,6 +165,7 @@
         dest.writeInt(mPrimitiveId);
         dest.writeFloat(mScale);
         dest.writeInt(mDelay);
+        dest.writeInt(mDelayType);
     }
 
     @Override
@@ -163,14 +179,16 @@
                 + "primitive=" + VibrationEffect.Composition.primitiveToString(mPrimitiveId)
                 + ", scale=" + mScale
                 + ", delay=" + mDelay
+                + ", delayType=" + VibrationEffect.Composition.delayTypeToString(mDelayType)
                 + '}';
     }
 
     /** @hide */
     @Override
     public String toDebugString() {
-        return String.format("Primitive=%s(scale=%.2f, delay=%dms)",
-                VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale, mDelay);
+        return String.format(Locale.ROOT, "Primitive=%s(scale=%.2f, %s=%dms)",
+                VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale,
+                toDelayTypeDebugString(mDelayType), mDelay);
     }
 
     @Override
@@ -180,12 +198,28 @@
         PrimitiveSegment that = (PrimitiveSegment) o;
         return mPrimitiveId == that.mPrimitiveId
                 && Float.compare(that.mScale, mScale) == 0
-                && mDelay == that.mDelay;
+                && mDelay == that.mDelay
+                && mDelayType == that.mDelayType;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mPrimitiveId, mScale, mDelay);
+        return Objects.hash(mPrimitiveId, mScale, mDelay, mDelayType);
+    }
+
+    private static boolean isValidDelayType(int delayType) {
+        return switch (delayType) {
+            case VibrationEffect.Composition.DELAY_TYPE_PAUSE,
+                 VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> true;
+            default -> false;
+        };
+    }
+
+    private static String toDelayTypeDebugString(int delayType) {
+        return switch (delayType) {
+            case VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> "startOffset";
+            default -> "pause";
+        };
     }
 
     @NonNull
diff --git a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
new file mode 100644
index 0000000..afaab55
--- /dev/null
+++ b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.vibrator;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.VibrationEffect;
+
+import java.util.Objects;
+
+/**
+ * Provides information about the vibrator hardware capabilities and limitations regarding
+ * waveform envelope effects. This includes:
+ * <ul>
+ * <li>Maximum number of control points supported.
+ * <li>Minimum and maximum duration for individual segments.
+ * <li>Maximum total duration for an envelope effect.
+ * </ul>
+ *
+ * <p>This information can be used to help construct waveform envelope effects with
+ * {@link VibrationEffect.WaveformEnvelopeBuilder}. When designing these effects, it is also
+ * recommended to check the {@link VibratorFrequencyProfile} for information about the supported
+ * frequency range and the vibrator's output response.
+ *
+ * @see VibrationEffect.WaveformEnvelopeBuilder
+ * @see VibratorFrequencyProfile
+ */
+@FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+public final class VibratorEnvelopeEffectInfo implements Parcelable {
+    private final int mMaxSize;
+    private final long mMinControlPointDurationMillis;
+    private final long mMaxControlPointDurationMillis;
+
+    VibratorEnvelopeEffectInfo(Parcel in) {
+        mMaxSize = in.readInt();
+        mMinControlPointDurationMillis = in.readLong();
+        mMaxControlPointDurationMillis = in.readLong();
+    }
+
+    /**
+     * Default constructor.
+     *
+     * @param maxSize                       The maximum number of control points supported for an
+     *                                      envelope effect.
+     * @param minControlPointDurationMillis The minimum duration supported between two control
+     *                                      points within an envelope effect.
+     * @param maxControlPointDurationMillis The maximum duration supported between two control
+     *                                      points within an envelope effect.
+     * @hide
+     */
+    public VibratorEnvelopeEffectInfo(int maxSize,
+            long minControlPointDurationMillis,
+            long maxControlPointDurationMillis) {
+        mMaxSize = maxSize;
+        mMinControlPointDurationMillis = minControlPointDurationMillis;
+        mMaxControlPointDurationMillis = maxControlPointDurationMillis;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mMaxSize);
+        dest.writeLong(mMinControlPointDurationMillis);
+        dest.writeLong(mMaxControlPointDurationMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof VibratorEnvelopeEffectInfo)) {
+            return false;
+        }
+        VibratorEnvelopeEffectInfo other = (VibratorEnvelopeEffectInfo) o;
+        return mMaxSize == other.mMaxSize
+                && mMinControlPointDurationMillis == other.mMinControlPointDurationMillis
+                && mMaxControlPointDurationMillis == other.mMaxControlPointDurationMillis;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMaxSize,
+                mMinControlPointDurationMillis,
+                mMaxControlPointDurationMillis);
+    }
+
+    @Override
+    public String toString() {
+        return "VibratorEnvelopeEffectInfo{"
+                + ", mMaxSize=" + mMaxSize
+                + ", mMinControlPointDurationMillis=" + mMinControlPointDurationMillis
+                + ", mMaxControlPointDurationMillis=" + mMaxControlPointDurationMillis
+                + '}';
+    }
+
+    @NonNull
+    public static final Creator<VibratorEnvelopeEffectInfo> CREATOR =
+            new Creator<VibratorEnvelopeEffectInfo>() {
+                @Override
+                public VibratorEnvelopeEffectInfo createFromParcel(Parcel in) {
+                    return new VibratorEnvelopeEffectInfo(in);
+                }
+
+                @Override
+                public VibratorEnvelopeEffectInfo[] newArray(int size) {
+                    return new VibratorEnvelopeEffectInfo[size];
+                }
+            };
+
+    /**
+     * Retrieves the maximum duration supported for an envelope effect, in milliseconds.
+     *
+     * <p>If the device supports envelope effects
+     * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+     * positive. Devices with envelope effects capabilities guarantees a maximum duration
+     * equivalent to the product of {@link #getMaxSize()} and
+     * {@link #getMaxControlPointDurationMillis()}. If the device does not support
+     * envelope effects, this method will return 0.
+     *
+     * @return The maximum duration (in milliseconds) allowed for an envelope effect, or 0 if
+     * envelope effects are not supported.
+     */
+    public long getMaxDurationMillis() {
+        return mMaxSize * mMaxControlPointDurationMillis;
+    }
+
+    /**
+     * Retrieves the maximum number of control points supported for an envelope effect.
+     *
+     * <p>If the device supports envelope effects
+     * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+     * positive. Devices with envelope effects capabilities guarantee support for a minimum of
+     * 16 control points. If the device does not support envelope effects, this method will
+     * return 0.
+     *
+     * @return the maximum number of control points allowed for an envelope effect, or 0 if
+     * envelope effects are not supported.
+     */
+    public int getMaxSize() {
+        return mMaxSize;
+    }
+
+    /**
+     * Retrieves the minimum duration supported between two control points within an envelope
+     * effect, in milliseconds.
+     *
+     * <p>If the device supports envelope effects
+     * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+     * positive. Devices with envelope effects capabilities guarantee support for durations down
+     * to at least 20 milliseconds. If the device does not support envelope effects,
+     * this method will return 0.
+     *
+     * @return the minimum allowed duration between two control points in an envelope effect,
+     * or 0 if envelope effects are not supported.
+     */
+    public long getMinControlPointDurationMillis() {
+        return mMinControlPointDurationMillis;
+    }
+
+    /**
+     * Retrieves the maximum duration supported between two control points within an envelope
+     * effect, in milliseconds.
+     *
+     * <p>If the device supports envelope effects
+     * (check {@link android.os.VibratorInfo#areEnvelopeEffectsSupported}), this value will be
+     * positive. Devices with envelope effects capabilities guarantee support for durations up to
+     * at least 1 second. If the device does not support envelope effects, this method
+     * will return 0.
+     *
+     * @return the maximum allowed duration between two control points in an envelope effect,
+     * or 0 if envelope effects are not supported.
+     */
+    public long getMaxControlPointDurationMillis() {
+        return mMaxControlPointDurationMillis;
+    }
+}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 33040be..0a35fe3 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -391,3 +391,21 @@
     description: "Batch noteOperations on the client to reduce binder call volume"
     bug: "366013082"
 }
+
+flag {
+    name: "supervision_role_permission_update_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "supervision"
+    description: "This flag is used to enable all the remaining permissions required to the supervision role"
+    bug: "367333883"
+}
+
+flag {
+    name: "permission_request_short_circuit_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "This flag is used to short circuit the request for permananently denied permissions"
+    bug: "378923900"
+}
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index 6f3e3d8..9fe0dda 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -16,20 +16,30 @@
 
 package android.security.advancedprotection;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.security.Flags;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 
@@ -45,6 +55,139 @@
 public final class AdvancedProtectionManager {
     private static final String TAG = "AdvancedProtectionMgr";
 
+    /**
+     * Advanced Protection's identifier for setting policies or restrictions in DevicePolicyManager.
+     *
+     * @hide */
+    public static final String ADVANCED_PROTECTION_SYSTEM_ENTITY =
+            "android.security.advancedprotection";
+
+    /**
+     * Feature identifier for disallowing 2G.
+     *
+     * @hide */
+    @SystemApi
+    public static final String FEATURE_ID_DISALLOW_CELLULAR_2G =
+            "android.security.advancedprotection.feature_disallow_2g";
+
+    /**
+     * Feature identifier for disallowing install of unknown sources.
+     *
+     * @hide */
+    @SystemApi
+    public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES =
+            "android.security.advancedprotection.feature_disallow_install_unknown_sources";
+
+    /**
+     * Feature identifier for disallowing USB.
+     *
+     * @hide */
+    @SystemApi
+    public static final String FEATURE_ID_DISALLOW_USB =
+            "android.security.advancedprotection.feature_disallow_usb";
+
+    /**
+     * Feature identifier for disallowing WEP.
+     *
+     * @hide */
+    @SystemApi
+    public static final String FEATURE_ID_DISALLOW_WEP =
+            "android.security.advancedprotection.feature_disallow_wep";
+
+    /**
+     * Feature identifier for enabling MTE.
+     *
+     * @hide */
+    @SystemApi
+    public static final String FEATURE_ID_ENABLE_MTE =
+            "android.security.advancedprotection.feature_enable_mte";
+
+    /** @hide */
+    @StringDef(prefix = { "FEATURE_ID_" }, value = {
+            FEATURE_ID_DISALLOW_CELLULAR_2G,
+            FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            FEATURE_ID_DISALLOW_USB,
+            FEATURE_ID_DISALLOW_WEP,
+            FEATURE_ID_ENABLE_MTE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FeatureId {}
+
+    private static final Set<String> ALL_FEATURE_IDS = Set.of(
+            FEATURE_ID_DISALLOW_CELLULAR_2G,
+            FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            FEATURE_ID_DISALLOW_USB,
+            FEATURE_ID_DISALLOW_WEP,
+            FEATURE_ID_ENABLE_MTE);
+
+    /**
+     * Activity Action: Show a dialog with disabled by advanced protection message.
+     * <p> If a user action or a setting toggle is disabled by advanced protection, this dialog can
+     * be triggered to let the user know about this.
+     * <p>
+     * Input:
+     * <p>{@link #EXTRA_SUPPORT_DIALOG_FEATURE}: The feature identifier.
+     * <p>{@link #EXTRA_SUPPORT_DIALOG_TYPE}: The type of the action.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide */
+    @SystemApi
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
+    public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG =
+            "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
+
+    /**
+     * A string extra used with {@link #createSupportIntent} to identify the feature that needs to
+     * show a support dialog explaining it was disabled by advanced protection.
+     *
+     * @hide */
+    @FeatureId
+    @SystemApi
+    public static final String EXTRA_SUPPORT_DIALOG_FEATURE =
+            "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
+
+    /**
+     * A string extra used with {@link #createSupportIntent} to identify the type of the action that
+     * needs to be explained in the support dialog.
+     *
+     * @hide */
+    @SupportDialogType
+    @SystemApi
+    public static final String EXTRA_SUPPORT_DIALOG_TYPE =
+            "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
+
+    /**
+     * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user performed an action that was
+     * blocked by advanced protection.
+     *
+     * @hide */
+    @SystemApi
+    public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION =
+            "android.security.advancedprotection.type_blocked_interaction";
+
+    /**
+     * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user pressed on a setting toggle
+     * that was disabled by advanced protection.
+     *
+     * @hide */
+    @SystemApi
+    public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING =
+            "android.security.advancedprotection.type_disabled_setting";
+
+    /** @hide */
+    @StringDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = {
+            SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
+            SUPPORT_DIALOG_TYPE_DISABLED_SETTING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SupportDialogType {}
+
+    private static final Set<String> ALL_SUPPORT_DIALOG_TYPES = Set.of(
+            SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
+            SUPPORT_DIALOG_TYPE_DISABLED_SETTING);
+
     private final ConcurrentHashMap<Callback, IAdvancedProtectionCallback>
             mCallbackMap = new ConcurrentHashMap<>();
 
@@ -164,6 +307,43 @@
     }
 
     /**
+     * Called by a feature to display a support dialog when a feature was disabled by advanced
+     * protection. This returns an intent that can be used with
+     * {@link Context#startActivity(Intent)} to display the dialog.
+     *
+     * <p>Note that this method doesn't check if the feature is actually disabled, i.e. this method
+     * will always return an intent.
+     *
+     * @param featureId The feature identifier.
+     * @param type The type of the feature describing the action that needs to be explained
+     *                 in the dialog or null for default explanation.
+     * @return Intent An intent to be used to start the dialog-activity that explains a feature was
+     *                disabled by advanced protection.
+     * @hide
+     */
+    @SystemApi
+    public @NonNull Intent createSupportIntent(@NonNull @FeatureId String featureId,
+            @Nullable @SupportDialogType String type) {
+        Objects.requireNonNull(featureId);
+        if (!ALL_FEATURE_IDS.contains(featureId)) {
+            throw new IllegalArgumentException(featureId + " is not a valid feature ID. See"
+                    + " FEATURE_ID_* APIs.");
+        }
+        if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
+            throw new IllegalArgumentException(type + " is not a valid type. See"
+                    + " SUPPORT_DIALOG_TYPE_* APIs.");
+        }
+
+        Intent intent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
+        intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, featureId);
+        if (type != null) {
+            intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type);
+        }
+        return intent;
+    }
+
+    /**
      * A callback class for monitoring changes to Advanced Protection state
      *
      * <p>To register a callback, implement this interface, and register it with
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index ce90121..09004b3 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -115,6 +115,14 @@
 }
 
 flag {
+    name: "protect_device_config_flags"
+    namespace: "psap_ai"
+    description: "Feature flag to limit adb shell to allowlisted flags"
+    bug: "364083026"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "keystore_grant_api"
     namespace: "hardware_backed_security"
     description: "Feature flag for exposing KeyStore grant APIs"
diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/forensic/ForensicEvent.java
index 90906ed..3d908cc 100644
--- a/core/java/android/security/forensic/ForensicEvent.java
+++ b/core/java/android/security/forensic/ForensicEvent.java
@@ -17,13 +17,17 @@
 package android.security.forensic;
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.app.admin.ConnectEvent;
+import android.app.admin.DnsEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.security.Flags;
-import android.util.ArrayMap;
 
-import java.util.Map;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * A class that represents a forensic event.
@@ -33,11 +37,24 @@
 public final class ForensicEvent implements Parcelable {
     private static final String TAG = "ForensicEvent";
 
-    @NonNull
-    private final String mType;
+    public static final int SECURITY_EVENT = 0;
+    public static final int NETWORK_EVENT_DNS = 1;
+    public static final int NETWORK_EVENT_CONNECT = 2;
 
-    @NonNull
-    private final Map<String, String> mKeyValuePairs;
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        ForensicEvent.SECURITY_EVENT,
+        ForensicEvent.NETWORK_EVENT_DNS,
+        ForensicEvent.NETWORK_EVENT_CONNECT,
+    })
+    public @interface EventType {}
+
+    @NonNull @EventType private final int mType;
+
+    private final SecurityEvent mSecurityEvent;
+    private final DnsEvent mNetworkEventDns;
+    private final ConnectEvent mNetworkEventConnect;
 
     public static final @NonNull Parcelable.Creator<ForensicEvent> CREATOR =
             new Parcelable.Creator<>() {
@@ -50,30 +67,99 @@
                 }
             };
 
-    public ForensicEvent(@NonNull String type, @NonNull Map<String, String> keyValuePairs) {
-        mType = type;
-        mKeyValuePairs = keyValuePairs;
+    public ForensicEvent(@NonNull SecurityEvent securityEvent) {
+        mType = SECURITY_EVENT;
+        mSecurityEvent = securityEvent;
+        mNetworkEventDns = null;
+        mNetworkEventConnect = null;
+    }
+
+    public ForensicEvent(@NonNull DnsEvent dnsEvent) {
+        mType = NETWORK_EVENT_DNS;
+        mNetworkEventDns = dnsEvent;
+        mSecurityEvent = null;
+        mNetworkEventConnect = null;
+    }
+
+    public ForensicEvent(@NonNull ConnectEvent connectEvent) {
+        mType = NETWORK_EVENT_CONNECT;
+        mNetworkEventConnect = connectEvent;
+        mSecurityEvent = null;
+        mNetworkEventDns = null;
     }
 
     private ForensicEvent(@NonNull Parcel in) {
-        mType = in.readString();
-        mKeyValuePairs = new ArrayMap<>(in.readInt());
-        in.readMap(mKeyValuePairs, getClass().getClassLoader(), String.class, String.class);
+        mType = in.readInt();
+        switch (mType) {
+            case SECURITY_EVENT:
+                mSecurityEvent = SecurityEvent.CREATOR.createFromParcel(in);
+                mNetworkEventDns = null;
+                mNetworkEventConnect = null;
+                break;
+            case NETWORK_EVENT_DNS:
+                mNetworkEventDns = DnsEvent.CREATOR.createFromParcel(in);
+                mSecurityEvent = null;
+                mNetworkEventConnect = null;
+                break;
+            case NETWORK_EVENT_CONNECT:
+                mNetworkEventConnect = ConnectEvent.CREATOR.createFromParcel(in);
+                mSecurityEvent = null;
+                mNetworkEventDns = null;
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid event type: " + mType);
+        }
     }
 
-    public String getType() {
+    /** Returns the type of the forensic event. */
+    @NonNull
+    public @EventType int getType() {
         return mType;
     }
 
-    public Map<String, String> getKeyValuePairs() {
-        return mKeyValuePairs;
+    /** Returns the SecurityEvent object. */
+    @NonNull
+    public SecurityEvent getSecurityEvent() {
+        if (mType == SECURITY_EVENT) {
+            return mSecurityEvent;
+        }
+        throw new IllegalArgumentException("Event type is not security event: " + mType);
+    }
+
+    /** Returns the DnsEvent object. */
+    @NonNull
+    public DnsEvent getDnsEvent() {
+        if (mType == NETWORK_EVENT_DNS) {
+            return mNetworkEventDns;
+        }
+        throw new IllegalArgumentException("Event type is not network DNS event: " + mType);
+    }
+
+    /** Returns the ConnectEvent object. */
+    @NonNull
+    public ConnectEvent getConnectEvent() {
+        if (mType == NETWORK_EVENT_CONNECT) {
+            return mNetworkEventConnect;
+        }
+        throw new IllegalArgumentException("Event type is not network connect event: " + mType);
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
-        out.writeString(mType);
-        out.writeInt(mKeyValuePairs.size());
-        out.writeMap(mKeyValuePairs);
+        out.writeInt(mType);
+        switch (mType) {
+            case SECURITY_EVENT:
+                out.writeParcelable(mSecurityEvent, flags);
+                break;
+            case NETWORK_EVENT_DNS:
+                out.writeParcelable(mNetworkEventDns, flags);
+                break;
+            case NETWORK_EVENT_CONNECT:
+                out.writeParcelable(mNetworkEventConnect, flags);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid event type: " + mType);
+        }
     }
 
     @FlaggedApi(Flags.FLAG_AFL_API)
@@ -86,7 +172,6 @@
     public String toString() {
         return "ForensicEvent{"
                 + "mType=" + mType
-                + ", mKeyValuePairs=" + mKeyValuePairs
                 + '}';
     }
 }
diff --git a/core/java/android/security/forensic/ForensicManager.java b/core/java/android/security/forensic/ForensicManager.java
new file mode 100644
index 0000000..9126182
--- /dev/null
+++ b/core/java/android/security/forensic/ForensicManager.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.forensic;
+
+import static android.Manifest.permission.MANAGE_FORENSIC_STATE;
+import static android.Manifest.permission.READ_FORENSIC_STATE;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.security.Flags;
+import android.util.Log;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * ForensicManager manages the forensic logging on Android devices.
+ * Upon user consent, forensic logging collects various device events for
+ * off-device investigation of potential device compromise.
+ * <p>
+ * Forensic logging can either be enabled ({@link #STATE_ENABLED}
+ * or disabled ({@link #STATE_DISABLED}).
+ * <p>
+ * The Forensic logs will be transferred to
+ * {@link android.security.forensic.ForensicEventTransport}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_AFL_API)
+@SystemService(Context.FORENSIC_SERVICE)
+public class ForensicManager {
+    private static final String TAG = "ForensicManager";
+
+    /** @hide */
+    @Target(ElementType.TYPE_USE)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_UNKNOWN,
+            STATE_DISABLED,
+            STATE_ENABLED
+    })
+    public @interface ForensicState {}
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ERROR_" }, value = {
+            ERROR_UNKNOWN,
+            ERROR_PERMISSION_DENIED,
+            ERROR_TRANSPORT_UNAVAILABLE,
+            ERROR_DATA_SOURCE_UNAVAILABLE
+    })
+    public @interface ForensicError {}
+
+    /**
+     * Indicates an unknown state
+     */
+    public static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN;
+
+    /**
+     * Indicates an state that the forensic is turned off.
+     */
+    public static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED;
+
+    /**
+     * Indicates an state that the forensic is turned on.
+     */
+    public static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED;
+
+    /**
+     * Indicates an unknown error
+     */
+    public static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN;
+
+    /**
+     * Indicates an error due to insufficient access rights.
+     */
+    public static final int ERROR_PERMISSION_DENIED =
+            IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
+
+    /**
+     * Indicates an error due to unavailability of the forensic event transport.
+     */
+    public static final int ERROR_TRANSPORT_UNAVAILABLE =
+            IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
+
+    /**
+     * Indicates an error due to unavailability of the data source.
+     */
+    public static final int ERROR_DATA_SOURCE_UNAVAILABLE =
+            IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
+
+
+    private final IForensicService mService;
+
+    private final ConcurrentHashMap<Consumer<Integer>, IForensicServiceStateCallback>
+            mStateCallbacks = new ConcurrentHashMap<>();
+
+    /**
+     * Constructor
+     *
+     * @param service A valid instance of IForensicService.
+     * @hide
+     */
+    public ForensicManager(IForensicService service) {
+        mService = service;
+    }
+
+    /**
+     * Add a callback to monitor the state of the ForensicService.
+     *
+     * @param executor The executor through which the callback should be invoked.
+     * @param callback The callback for state change.
+     *                 Once the callback is registered, the callback will be called
+     *                 to reflect the init state.
+     *                 The callback can be registered only once.
+     */
+    @RequiresPermission(READ_FORENSIC_STATE)
+    public void addStateCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ForensicState Consumer<Integer> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        if (mStateCallbacks.get(callback) != null) {
+            Log.d(TAG, "addStateCallback callback already present");
+            return;
+        }
+
+        final IForensicServiceStateCallback wrappedCallback =
+                new IForensicServiceStateCallback.Stub() {
+                    @Override
+                    public void onStateChange(int state) {
+                        executor.execute(() -> callback.accept(state));
+                    }
+                };
+        try {
+            mService.addStateCallback(wrappedCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        mStateCallbacks.put(callback, wrappedCallback);
+    }
+
+    /**
+     * Remove a callback to monitor the state of the ForensicService.
+     *
+     * @param callback The callback to remove.
+     */
+    @RequiresPermission(READ_FORENSIC_STATE)
+    public void removeStateCallback(@NonNull Consumer<@ForensicState Integer> callback) {
+        Objects.requireNonNull(callback);
+        if (!mStateCallbacks.containsKey(callback)) {
+            Log.d(TAG, "removeStateCallback callback not present");
+            return;
+        }
+
+        IForensicServiceStateCallback wrappedCallback = mStateCallbacks.get(callback);
+
+        try {
+            mService.removeStateCallback(wrappedCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        mStateCallbacks.remove(callback);
+    }
+
+    /**
+     * Enable forensic logging.
+     * If successful, ForensicService will transition to {@link #STATE_ENABLED} state.
+     * <p>
+     * When forensic logging is enabled, various device events will be collected and
+     * sent over to the registered {@link android.security.forensic.ForensicEventTransport}.
+     *
+     * @param executor The executor through which the callback should be invoked.
+     * @param callback The callback for the command result.
+     */
+    @RequiresPermission(MANAGE_FORENSIC_STATE)
+    public void enable(@NonNull @CallbackExecutor Executor executor,
+            @NonNull CommandCallback callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        try {
+            mService.enable(new IForensicServiceCommandCallback.Stub() {
+                @Override
+                public void onSuccess() {
+                    executor.execute(callback::onSuccess);
+                }
+
+                @Override
+                public void onFailure(int error) {
+                    executor.execute(() -> callback.onFailure(error));
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Disable forensic logging.
+     * If successful, ForensicService will transition to {@link #STATE_DISABLED}.
+     * <p>
+     * When forensic logging is disabled, device events will no longer be collected.
+     * Any events that have been collected but not yet sent to ForensicEventTransport
+     * will be transferred as a final batch.
+     *
+     * @param executor The executor through which the callback should be invoked.
+     * @param callback The callback for the command result.
+     */
+    @RequiresPermission(MANAGE_FORENSIC_STATE)
+    public void disable(@NonNull @CallbackExecutor Executor executor,
+            @NonNull CommandCallback callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        try {
+            mService.disable(new IForensicServiceCommandCallback.Stub() {
+                @Override
+                public void onSuccess() {
+                    executor.execute(callback::onSuccess);
+                }
+
+                @Override
+                public void onFailure(int error) {
+                    executor.execute(() -> callback.onFailure(error));
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback used in {@link #enable} and {@link #disable} to indicate the result of the command.
+     */
+    public interface CommandCallback {
+        /**
+         * Called when command succeeds.
+         */
+        void onSuccess();
+
+        /**
+         * Called when command fails.
+         * @param error The error number.
+         */
+        void onFailure(@ForensicError int error);
+    }
+}
diff --git a/core/java/android/security/forensic/IBackupTransport.aidl b/core/java/android/security/forensic/IForensicEventTransport.aidl
similarity index 96%
rename from core/java/android/security/forensic/IBackupTransport.aidl
rename to core/java/android/security/forensic/IForensicEventTransport.aidl
index c2cbc83..80e78eb 100644
--- a/core/java/android/security/forensic/IBackupTransport.aidl
+++ b/core/java/android/security/forensic/IForensicEventTransport.aidl
@@ -20,7 +20,7 @@
 import com.android.internal.infra.AndroidFuture;
 
 /** {@hide} */
-oneway interface IBackupTransport {
+oneway interface IForensicEventTransport {
     /**
      * Initialize the server side.
      */
diff --git a/core/java/android/security/forensic/IForensicService.aidl b/core/java/android/security/forensic/IForensicService.aidl
index a944b18..8039b26 100644
--- a/core/java/android/security/forensic/IForensicService.aidl
+++ b/core/java/android/security/forensic/IForensicService.aidl
@@ -24,9 +24,12 @@
  * @hide
  */
 interface IForensicService {
-    void monitorState(IForensicServiceStateCallback callback);
-    void makeVisible(IForensicServiceCommandCallback callback);
-    void makeInvisible(IForensicServiceCommandCallback callback);
+    @EnforcePermission("READ_FORENSIC_STATE")
+    void addStateCallback(IForensicServiceStateCallback callback);
+    @EnforcePermission("READ_FORENSIC_STATE")
+    void removeStateCallback(IForensicServiceStateCallback callback);
+    @EnforcePermission("MANAGE_FORENSIC_STATE")
     void enable(IForensicServiceCommandCallback callback);
+    @EnforcePermission("MANAGE_FORENSIC_STATE")
     void disable(IForensicServiceCommandCallback callback);
 }
diff --git a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl b/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl
index 7fa0c7f..6d1456e 100644
--- a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl
+++ b/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl
@@ -25,8 +25,8 @@
          UNKNOWN = 0,
          PERMISSION_DENIED = 1,
          INVALID_STATE_TRANSITION = 2,
-         BACKUP_TRANSPORT_UNAVAILABLE = 3,
-         DATA_SOURCE_UNAVAILABLE = 3,
+         TRANSPORT_UNAVAILABLE = 3,
+         DATA_SOURCE_UNAVAILABLE = 4,
      }
     void onSuccess();
     void onFailure(ErrorCode error);
diff --git a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl b/core/java/android/security/forensic/IForensicServiceStateCallback.aidl
index 0cda350..1b68c7b 100644
--- a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl
+++ b/core/java/android/security/forensic/IForensicServiceStateCallback.aidl
@@ -23,9 +23,8 @@
     @Backing(type="int")
     enum State{
         UNKNOWN = 0,
-        INVISIBLE = 1,
-        VISIBLE = 2,
-        ENABLED = 3,
+        DISABLED = 1,
+        ENABLED = 2,
     }
     void onStateChange(State state);
  }
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index 66e1f38..6c92991 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -103,3 +103,10 @@
     description: "Applies intentMatchingFlags while matching intents to application components"
     bug: "364354494"
 }
+
+flag {
+    name: "aapm_feature_disable_install_unknown_sources"
+    namespace: "responsible_apis"
+    description: "Android Advanced Protection Mode Feature: Disable Install Unknown Sources"
+    bug: "369361373"
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 98dda10..14a14e6 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -16,8 +16,10 @@
 
 package android.service.autofill;
 
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
 import static android.view.autofill.Helper.sVerbose;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -63,14 +65,21 @@
     private static final String TAG = "FillEventHistory";
 
     /**
-     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
+     * The ID of the autofill session that created the {@link FillResponse}.
+     *
+     * TODO: add this to the parcel.
      */
     private final int mSessionId;
 
     @Nullable private final Bundle mClientState;
     @Nullable List<Event> mEvents;
 
-    /** @hide */
+    /**
+     * Returns the unique identifier of this FillEventHistory.
+     *
+     * <p>This is used to differentiate individual FillEventHistory.
+     */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
     public int getSessionId() {
         return mSessionId;
     }
@@ -283,6 +292,13 @@
         /** All fields matched contents of datasets. */
         public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6;
 
+        /**
+         * Credential Manager is invoked instead of Autofill. When that happens, Save Dialog cannot
+         * be shown, and this will be populated in
+         */
+        @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+        public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7;
+
         /** @hide */
         @IntDef(prefix = { "NO_SAVE_UI_REASON_" }, value = {
                 NO_SAVE_UI_REASON_NONE,
@@ -310,11 +326,20 @@
         public static final int UI_TYPE_DIALOG = 3;
 
         /**
-         *  The autofill suggestion is shown os a credman bottom sheet
-         *  @hide
+         * The autofill suggestion is shown os a credman bottom sheet
+         *
+         * <p>Note, this was introduced as bottom sheet even though it applies to all credman UI
+         * types. Instead of exposing this directly to the public, the generic UI_TYPE_CREDMAN is
+         * introduced with the same number.
+         *
+         * @hide
          */
         public static final int UI_TYPE_CREDMAN_BOTTOM_SHEET = 4;
 
+        /** Credential Manager suggestions are shown instead of Autofill suggestion */
+        @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+        public static final int UI_TYPE_CREDMAN = 4;
+
         /** @hide */
         @IntDef(prefix = { "UI_TYPE_" }, value = {
                 UI_TYPE_UNKNOWN,
@@ -359,6 +384,13 @@
             return mEventType;
         }
 
+        /** Gets the {@code AutofillId} that's focused at the time of action */
+        @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+        @Nullable
+        public AutofillId getFocusedId() {
+            return null;
+        }
+
         /**
          * Returns the id of dataset the id was on.
          *
@@ -391,6 +423,17 @@
         }
 
         /**
+         * Returns which datasets were shown to the user.
+         *
+         * <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN}.
+         */
+        @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+        @NonNull
+        public Set<String> getShownDatasetIds() {
+            return Collections.emptySet();
+        }
+
+        /**
          * Returns which datasets were NOT selected by the user.
          *
          * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index b384b66..5471048 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -34,10 +34,14 @@
     void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
+    void onNotificationPostedFull(in StatusBarNotification sbn,
+            in NotificationRankingUpdate update);
     void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons);
     // stats only for assistant
     void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update, in NotificationStats stats, int reason);
+    void onNotificationRemovedFull(in StatusBarNotification sbn,
+                in NotificationRankingUpdate update, in NotificationStats stats, int reason);
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
@@ -48,7 +52,9 @@
 
     // assistants only
     void onNotificationEnqueuedWithChannel(in IStatusBarNotificationHolder notificationHolder, in NotificationChannel channel, in NotificationRankingUpdate update);
+    void onNotificationEnqueuedWithChannelFull(in StatusBarNotification sbn, in NotificationChannel channel, in NotificationRankingUpdate update);
     void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
+    void onNotificationSnoozedUntilContextFull(in StatusBarNotification sbn, String snoozeCriterionId);
     void onNotificationsSeen(in List<String> keys);
     void onPanelRevealed(int items);
     void onPanelHidden();
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 091b25a..0a9276c 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -423,7 +423,12 @@
                         + "Error receiving StatusBarNotification");
                 return;
             }
+            onNotificationEnqueuedWithChannelFull(sbn, channel, update);
+        }
 
+        @Override
+        public void onNotificationEnqueuedWithChannelFull(StatusBarNotification sbn,
+                NotificationChannel channel, NotificationRankingUpdate update) {
             applyUpdateLocked(update);
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
@@ -447,7 +452,12 @@
                 Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification");
                 return;
             }
+            onNotificationSnoozedUntilContextFull(sbn, snoozeCriterionId);
+        }
 
+        @Override
+        public void onNotificationSnoozedUntilContextFull(
+                StatusBarNotification sbn, String snoozeCriterionId) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = sbn;
             args.arg2 = snoozeCriterionId;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a8ab211..5d0ec73 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1490,7 +1490,12 @@
                 Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification");
                 return;
             }
+            onNotificationPostedFull(sbn, update);
+        }
 
+        @Override
+        public void onNotificationPostedFull(StatusBarNotification sbn,
+                NotificationRankingUpdate update) {
             try {
                 // convert icon metadata to legacy format for older clients
                 createLegacyIconExtras(sbn.getNotification());
@@ -1518,7 +1523,6 @@
                             mRankingMap).sendToTarget();
                 }
             }
-
         }
 
         @Override
@@ -1531,6 +1535,12 @@
                 Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
                 return;
             }
+            onNotificationRemovedFull(sbn, update, stats, reason);
+        }
+
+        @Override
+        public void onNotificationRemovedFull(StatusBarNotification sbn,
+                NotificationRankingUpdate update, NotificationStats stats, int reason) {
             if (sbn == null) {
                 Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification");
                 return;
@@ -1592,6 +1602,14 @@
         }
 
         @Override
+        public void onNotificationEnqueuedWithChannelFull(
+                StatusBarNotification sbn, NotificationChannel channel,
+                NotificationRankingUpdate update)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
         public void onNotificationsSeen(List<String> keys)
                 throws RemoteException {
             // no-op in the listener
@@ -1621,6 +1639,13 @@
         }
 
         @Override
+        public void onNotificationSnoozedUntilContextFull(
+                StatusBarNotification sbn, String snoozeCriterionId)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
         public void onNotificationExpansionChanged(
                 String key, boolean isUserAction, boolean isExpanded) {
             // no-op in the listener
@@ -1688,8 +1713,6 @@
                 Bundle feedback) {
             // no-op in the listener
         }
-
-
     }
 
     /**
diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
index 0dca78d..03e27b8 100644
--- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
+++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl
@@ -43,4 +43,6 @@
     oneway void unregisterWalletServiceEventListener(in WalletServiceEventListenerRequest request);
     // Request to get a PendingIntent to launch an activity from which the user can manage their cards.
     oneway void onTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks);
+    // Request to get a PendingIntent to launch an activity, triggered when the user performs a gesture.
+    oneway void onGestureTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks);
    }
\ No newline at end of file
diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
index 1b69ca1..61d7fd1 100644
--- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
+++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl
@@ -37,4 +37,6 @@
     oneway void onWalletServiceEvent(in WalletServiceEvent event);
     // Called in response to onTargetActivityIntentRequested. May only be called once per request.
     oneway void onTargetActivityPendingIntentReceived(in PendingIntent pendingIntent);
+    //Called in response to onGesturePendingIntent
+    oneway void onGestureTargetActivityPendingIntentReceived(in PendingIntent pendingIntent);
 }
\ No newline at end of file
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
index faa5b2f..b5251db 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java
@@ -17,6 +17,7 @@
 package android.service.quickaccesswallet;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -181,6 +182,23 @@
     }
 
     /**
+     * Gets the {@link PendingIntent} provided by QuickAccessWalletService to be sent when the user
+     * launches Wallet via gesture.
+     */
+    @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+    void getGestureTargetActivityPendingIntent(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull GesturePendingIntentCallback gesturePendingIntentCallback);
+
+    /** Callback interface for getGesturePendingIntent. */
+    @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+    interface GesturePendingIntentCallback {
+        /** Callback method for getGesturePendingIntent */
+        @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+        void onGesturePendingIntentRetrieved(@Nullable PendingIntent pendingIntent);
+    }
+
+    /**
      * The manifest entry for the QuickAccessWalletService may also publish information about the
      * activity that hosts the Wallet view. This is typically the home screen of the Wallet
      * application.
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index a59f026..97a4bef 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -267,6 +267,34 @@
     }
 
     @Override
+    public void getGestureTargetActivityPendingIntent(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull GesturePendingIntentCallback gesturePendingIntentCallback) {
+        BaseCallbacks callbacks =
+                new BaseCallbacks() {
+                    @Override
+                    public void onGestureTargetActivityPendingIntentReceived(
+                            PendingIntent pendingIntent) {
+                        if (!Flags.launchWalletOptionOnPowerDoubleTap()) {
+                            return;
+                        }
+                        executor.execute(
+                                () ->
+                                        gesturePendingIntentCallback
+                                                .onGesturePendingIntentRetrieved(pendingIntent));
+                    }
+                };
+
+        executeApiCall(
+                new ApiCaller("getGestureTargetActivityPendingIntent") {
+                    @Override
+                    void performApiCall(IQuickAccessWalletService service) throws RemoteException {
+                        service.onGestureTargetActivityIntentRequested(callbacks);
+                    }
+                });
+    }
+
+    @Override
     @Nullable
     public Intent createWalletSettingsIntent() {
         if (mServiceInfo == null) {
@@ -506,5 +534,9 @@
         public void onTargetActivityPendingIntentReceived(PendingIntent pendingIntent) {
             throw new IllegalStateException();
         }
+
+        public void onGestureTargetActivityPendingIntentReceived(PendingIntent pendingIntent) {
+            throw new IllegalStateException();
+        }
     }
 }
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
index 36fa21c..90136ae 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java
@@ -16,6 +16,9 @@
 
 package android.service.quickaccesswallet;
 
+import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -247,6 +250,19 @@
                             callbacks));
         }
 
+        @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+        @Override
+        public void onGestureTargetActivityIntentRequested(
+                @NonNull IQuickAccessWalletServiceCallbacks callbacks) {
+            if (launchWalletOptionOnPowerDoubleTap()) {
+                mHandler.post(
+                        () ->
+                                QuickAccessWalletService.this
+                                        .onGestureTargetActivityIntentRequestedInternal(
+                                                callbacks));
+            }
+        }
+
         public void registerWalletServiceEventListener(
                 @NonNull WalletServiceEventListenerRequest request,
                 @NonNull IQuickAccessWalletServiceCallbacks callback) {
@@ -275,6 +291,20 @@
         }
     }
 
+    private void onGestureTargetActivityIntentRequestedInternal(
+            IQuickAccessWalletServiceCallbacks callbacks) {
+        if (!Flags.launchWalletOptionOnPowerDoubleTap()) {
+            return;
+        }
+
+        try {
+            callbacks.onGestureTargetActivityPendingIntentReceived(
+                    getGestureTargetActivityPendingIntent());
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error", e);
+        }
+    }
+
     @Override
     @Nullable
     public IBinder onBind(@NonNull Intent intent) {
@@ -349,6 +379,18 @@
         return null;
     }
 
+    /**
+     * Specify a {@link PendingIntent} to be launched on user gesture.
+     *
+     * <p>The pending intent will be sent when the user performs a gesture to open Wallet.
+     * The pending intent should launch an activity.
+     */
+    @Nullable
+    @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP)
+    public PendingIntent getGestureTargetActivityPendingIntent() {
+        return null;
+    }
+
     private void sendWalletServiceEventInternal(WalletServiceEvent serviceEvent) {
         if (mEventListener == null) {
             Log.i(TAG, "No dismiss listener registered");
diff --git a/core/java/android/service/quickaccesswallet/flags.aconfig b/core/java/android/service/quickaccesswallet/flags.aconfig
index 07311d5..75a9309 100644
--- a/core/java/android/service/quickaccesswallet/flags.aconfig
+++ b/core/java/android/service/quickaccesswallet/flags.aconfig
@@ -3,7 +3,7 @@
 
 flag {
     name: "launch_wallet_option_on_power_double_tap"
-    namespace: "wallet_integrations"
+    namespace: "wallet_integration"
     description: "Option to launch the Wallet app on double-tap of the power button"
     bug: "378469025"
 }
\ No newline at end of file
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index 7b48a16..4c59a85 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -18,6 +18,7 @@
 
 import android.annotation.BytesLong;
 import android.annotation.CurrentTimeMillisLong;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,6 +29,7 @@
 import android.util.Range;
 import android.util.RecurrenceRule;
 
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
@@ -83,6 +85,33 @@
     /** Value indicating a timestamp is unknown. */
     public static final long TIME_UNKNOWN = -1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "SUBSCRIPTION_STATUS_" }, value = {
+            SUBSCRIPTION_STATUS_UNKNOWN,
+            SUBSCRIPTION_STATUS_ACTIVE,
+            SUBSCRIPTION_STATUS_INACTIVE,
+            SUBSCRIPTION_STATUS_TRIAL,
+            SUBSCRIPTION_STATUS_SUSPENDED
+    })
+    public @interface SubscriptionStatus {}
+
+    /** Subscription status is unknown. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0;
+    /** Subscription is active. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public static final int SUBSCRIPTION_STATUS_ACTIVE = 1;
+    /** Subscription is inactive. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public static final int SUBSCRIPTION_STATUS_INACTIVE = 2;
+    /** Subscription is in a trial period. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public static final int SUBSCRIPTION_STATUS_TRIAL = 3;
+    /** Subscription is suspended. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4;
+
     private final RecurrenceRule cycleRule;
     private CharSequence title;
     private CharSequence summary;
@@ -91,6 +120,7 @@
     private long dataUsageBytes = BYTES_UNKNOWN;
     private long dataUsageTime = TIME_UNKNOWN;
     private @NetworkType int[] networkTypes;
+    private int mSubscriptionStatus = SUBSCRIPTION_STATUS_UNKNOWN;
 
     private SubscriptionPlan(RecurrenceRule cycleRule) {
         this.cycleRule = Preconditions.checkNotNull(cycleRule);
@@ -107,6 +137,7 @@
         dataUsageBytes = source.readLong();
         dataUsageTime = source.readLong();
         networkTypes = source.createIntArray();
+        mSubscriptionStatus = source.readInt();
     }
 
     @Override
@@ -124,6 +155,7 @@
         dest.writeLong(dataUsageBytes);
         dest.writeLong(dataUsageTime);
         dest.writeIntArray(networkTypes);
+        dest.writeInt(mSubscriptionStatus);
     }
 
     @Override
@@ -137,13 +169,14 @@
                 .append(" dataUsageBytes=").append(dataUsageBytes)
                 .append(" dataUsageTime=").append(dataUsageTime)
                 .append(" networkTypes=").append(Arrays.toString(networkTypes))
+                .append(" subscriptionStatus=").append(mSubscriptionStatus)
                 .append("}").toString();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior,
-                dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes));
+                dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes), mSubscriptionStatus);
     }
 
     @Override
@@ -157,7 +190,8 @@
                     && dataLimitBehavior == other.dataLimitBehavior
                     && dataUsageBytes == other.dataUsageBytes
                     && dataUsageTime == other.dataUsageTime
-                    && Arrays.equals(networkTypes, other.networkTypes);
+                    && Arrays.equals(networkTypes, other.networkTypes)
+                    && mSubscriptionStatus == other.mSubscriptionStatus;
         }
         return false;
     }
@@ -179,6 +213,13 @@
         return cycleRule;
     }
 
+    /** Return the end date of this plan, or null if no end date exists. */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public @Nullable ZonedDateTime getPlanEndDate() {
+        // ZonedDateTime is immutable, so no need to create a defensive copy.
+        return cycleRule.end;
+    }
+
     /** Return the short title of this plan. */
     public @Nullable CharSequence getTitle() {
         return title;
@@ -238,6 +279,16 @@
     }
 
     /**
+     * Returns the status of the subscription plan.
+     *
+     * @return The subscription status, or {@link #SUBSCRIPTION_STATUS_UNKNOWN} if not available.
+     */
+    @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+    public @SubscriptionStatus int getSubscriptionStatus() {
+        return mSubscriptionStatus;
+    }
+
+    /**
      * Builder for a {@link SubscriptionPlan}.
      */
     public static class Builder {
@@ -382,5 +433,21 @@
                     TelephonyManager.getAllNetworkTypes().length);
             return this;
         }
+
+        /**
+         * Set the subscription status.
+         *
+         * @param subscriptionStatus the current subscription status
+         */
+        @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE)
+        public @NonNull Builder setSubscriptionStatus(@SubscriptionStatus int subscriptionStatus) {
+            if (subscriptionStatus < SUBSCRIPTION_STATUS_UNKNOWN
+                    || subscriptionStatus > SUBSCRIPTION_STATUS_SUSPENDED) {
+                throw new IllegalArgumentException(
+                        "Subscription status must be defined with a valid value");
+            }
+            plan.mSubscriptionStatus = subscriptionStatus;
+            return this;
+        }
     }
 }
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
deleted file mode 100644
index ca88764..0000000
--- a/core/java/android/text/ClientFlags.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-/**
- * An aconfig feature flags that can be accessible from application process without
- * ContentProvider IPCs.
- *
- * When you add new flags, you have to add flag string to {@link TextFlags#TEXT_ACONFIGS_FLAGS}.
- *
- * TODO(nona): Remove this class.
- * @hide
- */
-public class ClientFlags {
-}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index ae12132..a42eece 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -614,7 +614,7 @@
                 if (style[j] instanceof TypefaceSpan) {
                     String s = ((TypefaceSpan) style[j]).getFamily();
 
-                    if (s.equals("monospace")) {
+                    if ("monospace".equals(s)) {
                         out.append("</tt>");
                     }
                 }
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
deleted file mode 100644
index f69a333..0000000
--- a/core/java/android/text/TextFlags.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.annotation.NonNull;
-import android.app.AppGlobals;
-
-/**
- * Flags in the "text" namespace.
- *
- * TODO(nona): Remove this class.
- * @hide
- */
-public final class TextFlags {
-
-    /**
-     * The name space of the "text" feature.
-     *
-     * This needs to move to DeviceConfig constant.
-     */
-    public static final String NAMESPACE = "text";
-
-    /**
-     * Whether we use the new design of context menu.
-     */
-    public static final String ENABLE_NEW_CONTEXT_MENU =
-            "TextEditing__enable_new_context_menu";
-
-    /**
-     * The key name used in app core settings for {@link #ENABLE_NEW_CONTEXT_MENU}.
-     */
-    public static final String KEY_ENABLE_NEW_CONTEXT_MENU = "text__enable_new_context_menu";
-
-    /**
-     * Default value for the flag {@link #ENABLE_NEW_CONTEXT_MENU}.
-     */
-    public static final boolean ENABLE_NEW_CONTEXT_MENU_DEFAULT = true;
-
-    /**
-     * List of text flags to be transferred to the application process.
-     */
-    public static final String[] TEXT_ACONFIGS_FLAGS = {
-    };
-
-    /**
-     * List of the default values of the text flags.
-     *
-     * The order must be the same to the TEXT_ACONFIG_FLAGS.
-     */
-    public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = {
-    };
-
-    /**
-     * Get a key for the feature flag.
-     */
-    public static String getKeyForFlag(@NonNull String flag) {
-        return "text__" + flag;
-    }
-
-    /**
-     * Return true if the feature flag is enabled.
-     */
-    public static boolean isFeatureEnabled(@NonNull String flag) {
-        return AppGlobals.getIntCoreSetting(
-                getKeyForFlag(flag), 0 /* aconfig is false by default */) != 0;
-    }
-}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 032f592..cb72b97 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -50,6 +50,7 @@
 import android.text.style.LineBreakConfigSpan;
 import android.text.style.LineHeightSpan;
 import android.text.style.LocaleSpan;
+import android.text.style.NoWritingToolsSpan;
 import android.text.style.ParagraphStyle;
 import android.text.style.QuoteSpan;
 import android.text.style.RelativeSizeSpan;
@@ -817,7 +818,9 @@
     /** @hide */
     public static final int LINE_BREAK_CONFIG_SPAN = 30;
     /** @hide */
-    public static final int LAST_SPAN = LINE_BREAK_CONFIG_SPAN;
+    public static final int NO_WRITING_TOOLS_SPAN = 31;
+    /** @hide */
+    public static final int LAST_SPAN = NO_WRITING_TOOLS_SPAN;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -1025,6 +1028,10 @@
                     span = LineBreakConfigSpan.CREATOR.createFromParcel(p);
                     break;
 
+                case NO_WRITING_TOOLS_SPAN:
+                    span = NoWritingToolsSpan.CREATOR.createFromParcel(p);
+                    break;
+
                 default:
                     throw new RuntimeException("bogus span encoding " + kind);
                 }
diff --git a/core/java/android/text/style/NoWritingToolsSpan.java b/core/java/android/text/style/NoWritingToolsSpan.java
new file mode 100644
index 0000000..90f85aa
--- /dev/null
+++ b/core/java/android/text/style/NoWritingToolsSpan.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.style;
+
+import static android.view.inputmethod.Flags.FLAG_WRITING_TOOLS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
+
+/**
+ * A span that signals to IMEs that writing tools should not modify the text.
+ *
+ * <p>For example, a text field may contain a mix of user input text and quoted text. The app
+ * can apply {@code NoWritingToolsSpan} to the quoted text so that the IME knows that writing
+ * tools should only rewrite the user input text, and not modify the quoted text.
+ */
+@FlaggedApi(FLAG_WRITING_TOOLS)
+public final class NoWritingToolsSpan implements ParcelableSpan {
+
+    /**
+     * Creates a {@link NoWritingToolsSpan}.
+     */
+    public NoWritingToolsSpan() {
+    }
+
+    @Override
+    public int getSpanTypeId() {
+        return getSpanTypeIdInternal();
+    }
+
+    /** @hide */
+    @Override
+    public int getSpanTypeIdInternal() {
+        return TextUtils.NO_WRITING_TOOLS_SPAN;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        writeToParcelInternal(dest, flags);
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
+    }
+
+    @Override
+    public String toString() {
+        return "NoWritingToolsSpan{}";
+    }
+
+    @NonNull
+    public static final Creator<NoWritingToolsSpan> CREATOR = new Creator<>() {
+
+        @Override
+        public NoWritingToolsSpan createFromParcel(Parcel source) {
+            return new NoWritingToolsSpan();
+        }
+
+        @Override
+        public NoWritingToolsSpan[] newArray(int size) {
+            return new NoWritingToolsSpan[size];
+        }
+    };
+}
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 174e0c8..7ee0ff1 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -649,7 +649,6 @@
         }
         if (index > 0 && mHashes[index-1] > hash) {
             RuntimeException e = new RuntimeException("here");
-            e.fillInStackTrace();
             Log.w(TAG, "New hash " + hash
                     + " is before end of array hash " + mHashes[index-1]
                     + " at index " + index + (DEBUG ? " key " + key : ""), e);
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index bfbca07..1344bb9 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -526,7 +526,6 @@
             // Cannot optimize since it would break the sorted order - fallback to add()
             if (DEBUG) {
                 RuntimeException e = new RuntimeException("here");
-                e.fillInStackTrace();
                 Log.w(TAG, "New hash " + hash
                         + " is before end of array hash " + mHashes[index - 1]
                         + " at index " + index, e);
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 5406cf5..264db4a 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -15,9 +15,11 @@
  */
 package android.view;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.UiThread;
 import android.content.Context;
 import android.graphics.Rect;
@@ -29,6 +31,8 @@
 
 import com.android.window.flags.Flags;
 
+import java.util.concurrent.Executor;
+
 /**
  * Provides an interface to the root-Surface of a View Hierarchy or Window. This
  * is used in combination with the {@link android.view.SurfaceControl} API to enable
@@ -202,4 +206,21 @@
         throw new UnsupportedOperationException("The getInputTransferToken needs to be "
                 + "implemented before making this call.");
     }
+
+    /**
+     * Registers a {@link OnJankDataListener} to receive jank classification data about rendered
+     * frames.
+     *
+     * @param executor The executor on which the listener will be invoked.
+     * @param listener The listener to add.
+     * @return The {@link OnJankDataListenerRegistration} for the listener.
+     */
+    @NonNull
+    @FlaggedApi(Flags.FLAG_JANK_API)
+    @SuppressLint("PairedRegistration")
+    default SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SurfaceControl.OnJankDataListener listener) {
+        return SurfaceControl.OnJankDataListenerRegistration.NONE;
+    }
 }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 7e24749..8cb96ae 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -189,6 +189,11 @@
     @UnsupportedAppUsage
     private long mLastFrameTimeNanos;
 
+    // Keeps track of the last scheduled frame time without additional offsets
+    // added from buffer stuffing recovery. Used to compare timing of vsyncs to
+    // determine idle state.
+    private long mLastNoOffsetFrameTimeNanos;
+
     /** DO NOT USE since this will not updated when screen refresh changes. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
             publicAlternatives = "Use {@link android.view.Display#getRefreshRate} instead")
@@ -203,6 +208,50 @@
     private final FrameData mFrameData = new FrameData();
     private volatile boolean mInDoFrameCallback = false;
 
+    private static class BufferStuffingData {
+        enum RecoveryAction {
+            // No recovery
+            NONE,
+            // Recovery has started, adds a negative offset
+            OFFSET,
+            // Recovery has started, delays a frame to return buffer count
+            // back toward threshold.
+            DELAY_FRAME
+        }
+        // The maximum number of times frames will be delayed per buffer stuffing event.
+        // Since buffer stuffing can persist for several consecutive frames following the
+        // initial missed frame, we want to adjust the timeline with enough frame delays and
+        // offsets to return the queued buffer count back to threshold.
+        public static final int MAX_FRAME_DELAYS = 3;
+
+        // Whether buffer stuffing recovery has begun. Recovery can only end
+        // when events are idle.
+        public boolean isRecovering = false;
+
+        // The number of frames delayed so far during recovery. Used to compare with
+        // MAX_FRAME_DELAYS to safeguard against excessive frame delays during recovery.
+        // Also used as unique cookie for tracing.
+        public int numberFrameDelays = 0;
+
+        // The number of additional frame delays scheduled during recovery to wait for the next
+        // vsync. These are scheduled when frame times appear to go backward or frames are
+        // being skipped due to FPSDivisor.
+        public int numberWaitsForNextVsync = 0;
+
+        /**
+         * After buffer stuffing recovery has ended with a detected idle state, the
+         * recovery data trackers can be reset in preparation for any future
+         * stuffing events.
+         */
+        public void reset() {
+            isRecovering = false;
+            numberFrameDelays = 0;
+            numberWaitsForNextVsync = 0;
+        }
+    }
+
+    private final BufferStuffingData mBufferStuffingData = new BufferStuffingData();
+
     /**
      * Contains information about the current frame for jank-tracking,
      * mainly timings of key events along with a bit of metadata about
@@ -850,13 +899,99 @@
         Trace.traceEnd(Trace.TRACE_TAG_VIEW);
     }
 
+    // Conducts logic for beginning or ending buffer stuffing recovery.
+    // Returns an enum for the recovery action that should be taken in doFrame().
+    BufferStuffingData.RecoveryAction checkBufferStuffingRecovery(long frameTimeNanos,
+            DisplayEventReceiver.VsyncEventData vsyncEventData) {
+        // Canned animations can recover from buffer stuffing whenever more
+        // than 2 buffers are queued.
+        if (vsyncEventData.numberQueuedBuffers > 2) {
+            mBufferStuffingData.isRecovering = true;
+            // Intentional frame delay that can happen at most MAX_FRAME_DELAYS times per
+            // buffer stuffing event until the buffer count returns to threshold. The
+            // delayed frames are compensated for by the negative offsets added to the
+            // animation timestamps.
+            if (mBufferStuffingData.numberFrameDelays < mBufferStuffingData.MAX_FRAME_DELAYS) {
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                    Trace.asyncTraceForTrackBegin(
+                            Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", "Thread "
+                            + android.os.Process.myTid() + ", recover frame #"
+                            + mBufferStuffingData.numberFrameDelays,
+                            mBufferStuffingData.numberFrameDelays);
+                }
+                mBufferStuffingData.numberFrameDelays++;
+                scheduleVsyncLocked();
+                return BufferStuffingData.RecoveryAction.DELAY_FRAME;
+            }
+        }
+
+        if (mBufferStuffingData.isRecovering) {
+            // Includes an additional expected frame delay from the natural scheduling
+            // of the next vsync event.
+            int totalFrameDelays = mBufferStuffingData.numberFrameDelays
+                    + mBufferStuffingData.numberWaitsForNextVsync + 1;
+            long vsyncsSinceLastCallback = mLastFrameIntervalNanos > 0
+                    ? (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos : 0;
+
+            // Detected idle state due to a longer inactive period since the last vsync callback
+            // than the total expected number of vsync frame delays. End buffer stuffing recovery.
+            // There are no frames to animate and offsets no longer need to be added
+            // since the idle state gives the animation a chance to catch up.
+            if (vsyncsSinceLastCallback > totalFrameDelays) {
+                if (DEBUG_JANK) {
+                    Log.d(TAG, "End buffer stuffing recovery");
+                }
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                    for (int i = 0; i < mBufferStuffingData.numberFrameDelays; i++) {
+                        Trace.asyncTraceForTrackEnd(
+                                Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", i);
+                    }
+                }
+                mBufferStuffingData.reset();
+
+            } else {
+                if (DEBUG_JANK) {
+                    Log.d(TAG, "Adjust animation timeline with a negative offset");
+                }
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                    Trace.instantForTrack(
+                            Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery",
+                            "Negative offset added to animation");
+                }
+                return BufferStuffingData.RecoveryAction.OFFSET;
+            }
+        }
+        return BufferStuffingData.RecoveryAction.NONE;
+    }
+
     void doFrame(long frameTimeNanos, int frame,
             DisplayEventReceiver.VsyncEventData vsyncEventData) {
         final long startNanos;
         final long frameIntervalNanos = vsyncEventData.frameInterval;
         boolean resynced = false;
+        long offsetFrameTimeNanos = frameTimeNanos;
+
+        // Evaluate if buffer stuffing recovery needs to start or end, and
+        // what actions need to be taken for recovery.
+        switch (checkBufferStuffingRecovery(frameTimeNanos, vsyncEventData)) {
+            case NONE:
+                // Without buffer stuffing recovery, offsetFrameTimeNanos is
+                // synonymous with frameTimeNanos.
+                break;
+            case OFFSET:
+                // Add animation offset. Used to update frame timeline with
+                // offset before jitter is calculated.
+                offsetFrameTimeNanos = frameTimeNanos - frameIntervalNanos;
+                break;
+            case DELAY_FRAME:
+                // Intentional frame delay to help restore queued buffer count to threshold.
+                return;
+            default:
+                break;
+        }
+
         try {
-            FrameTimeline timeline = mFrameData.update(frameTimeNanos, vsyncEventData);
+            FrameTimeline timeline = mFrameData.update(offsetFrameTimeNanos, vsyncEventData);
             if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                 Trace.traceBegin(
                         Trace.TRACE_TAG_VIEW, "Choreographer#doFrame " + timeline.mVsyncId);
@@ -867,15 +1002,18 @@
                     traceMessage("Frame not scheduled");
                     return; // no work to do
                 }
+                mLastNoOffsetFrameTimeNanos = frameTimeNanos;
 
                 if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
                     mDebugPrintNextFrameTimeDelta = false;
                     Log.d(TAG, "Frame time delta: "
-                            + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
+                            + ((offsetFrameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
                 }
 
-                long intendedFrameTimeNanos = frameTimeNanos;
+                long intendedFrameTimeNanos = offsetFrameTimeNanos;
                 startNanos = System.nanoTime();
+                // Calculating jitter involves using the original frame time without
+                // adjustments from buffer stuffing
                 final long jitterNanos = startNanos - frameTimeNanos;
                 if (jitterNanos >= frameIntervalNanos) {
                     frameTimeNanos = startNanos;
@@ -899,6 +1037,13 @@
                                     + " ms in the past.");
                         }
                     }
+                    if (mBufferStuffingData.isRecovering) {
+                        frameTimeNanos -= frameIntervalNanos;
+                        if (DEBUG_JANK) {
+                            Log.d(TAG, "Adjusted animation timeline with a negative offset after"
+                                    + " jitter calculation");
+                        }
+                    }
                     timeline = mFrameData.update(
                             frameTimeNanos, mDisplayEventReceiver, jitterNanos);
                     resynced = true;
@@ -910,6 +1055,9 @@
                                 + "previously skipped frame.  Waiting for next vsync.");
                     }
                     traceMessage("Frame time goes backward");
+                    if (mBufferStuffingData.isRecovering) {
+                        mBufferStuffingData.numberWaitsForNextVsync++;
+                    }
                     scheduleVsyncLocked();
                     return;
                 }
@@ -918,6 +1066,9 @@
                     long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
                     if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
                         traceMessage("Frame skipped due to FPSDivisor");
+                        if (mBufferStuffingData.isRecovering) {
+                            mBufferStuffingData.numberWaitsForNextVsync++;
+                        }
                         scheduleVsyncLocked();
                         return;
                     }
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index fc7a65d..bb233d2 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -207,6 +207,8 @@
         // reasonable timestamps.
         public int frameTimelinesLength = 1;
 
+        public int numberQueuedBuffers = 0;
+
         VsyncEventData() {
             frameTimelines = new FrameTimeline[FRAME_TIMELINES_CAPACITY];
             for (int i = 0; i < frameTimelines.length; i++) {
@@ -217,11 +219,13 @@
         // Called from native code.
         @SuppressWarnings("unused")
         VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex,
-                int frameTimelinesLength, long frameInterval) {
+                int frameTimelinesLength, long frameInterval,
+                int numberQueuedBuffers) {
             this.frameTimelines = frameTimelines;
             this.preferredFrameTimelineIndex = preferredFrameTimelineIndex;
             this.frameTimelinesLength = frameTimelinesLength;
             this.frameInterval = frameInterval;
+            this.numberQueuedBuffers = numberQueuedBuffers;
         }
 
         void copyFrom(VsyncEventData other) {
@@ -231,6 +235,7 @@
             for (int i = 0; i < frameTimelines.length; i++) {
                 frameTimelines[i].copyFrom(other.frameTimelines[i]);
             }
+            numberQueuedBuffers = other.numberQueuedBuffers;
         }
 
         public FrameTimeline preferredFrameTimeline() {
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 9e25a3e..58b2a67 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -18,10 +18,13 @@
 
 import static android.graphics.FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 
+import com.android.window.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -177,6 +180,16 @@
     public static final int DEADLINE = 13;
 
     /**
+     * Metric identifier for the frame's VSync identifier.
+     * <p>
+     * The id that corresponds to the chosen frame timeline, used to correlate a frame produced
+     * by HWUI with the timeline data from the compositor.
+     * </p>
+     */
+    @FlaggedApi(Flags.FLAG_JANK_API)
+    public static final int FRAME_TIMELINE_VSYNC_ID = 14;
+
+    /**
      * Identifiers for metrics available for each frame.
      *
      * {@see #getMetric(int)}
@@ -337,7 +350,8 @@
      * @return the value of the metric or -1 if it is not available.
      */
     public long getMetric(@Metric int id) {
-        if (id < UNKNOWN_DELAY_DURATION || id > DEADLINE) {
+        if (id < UNKNOWN_DELAY_DURATION
+                || id > (Flags.jankApi() ? FRAME_TIMELINE_VSYNC_ID : DEADLINE)) {
             return -1;
         }
 
@@ -351,6 +365,8 @@
             return mTimingData[Index.INTENDED_VSYNC];
         } else if (id == VSYNC_TIMESTAMP) {
             return mTimingData[Index.VSYNC];
+        } else if (id == FRAME_TIMELINE_VSYNC_ID) {
+            return mTimingData[Index.FRAME_TIMELINE_VSYNC_ID];
         }
 
         int durationsIdx = 2 * id;
@@ -358,4 +374,3 @@
                 - mTimingData[DURATIONS[durationsIdx]];
     }
 }
-
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 206c737..d56768d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -22,6 +22,7 @@
 import static android.graphics.Matrix.MSKEW_Y;
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.flags.Flags.bufferStuffingRecovery;
 import static android.view.SurfaceControlProto.HASH_CODE;
 import static android.view.SurfaceControlProto.LAYER_ID;
 import static android.view.SurfaceControlProto.NAME;
@@ -410,8 +411,19 @@
 
     /**
      * Jank information to be fed back via {@link OnJankDataListener}.
-     * @hide
+     * <p>
+     * Apps may register a {@link OnJankDataListener} to get periodic batches of jank classification
+     * data from the (<a
+     * href="https://source.android.com/docs/core/graphics/surfaceflinger-windowmanagersystem">
+     * composer</a> regarding rendered frames. A frame is considered janky if it did not reach the
+     * display at the intended time, typically due to missing a rendering deadline. This API
+     * provides information that can be used to identify the root cause of the scheduling misses
+     * and provides overall frame scheduling statistics.
+     * <p>
+     * This API can be used in conjunction with the {@link FrameMetrics} API by associating jank
+     * classification data with {@link FrameMetrics} data via the frame VSync id.
      */
+    @FlaggedApi(Flags.FLAG_JANK_API)
     public static class JankData {
 
         /**
@@ -428,29 +440,105 @@
         @Retention(RetentionPolicy.SOURCE)
         public @interface JankType {}
 
-        // No Jank
+        /**
+         * No jank detected, the frame was on time.
+         */
         public static final int JANK_NONE = 0;
-        // Jank caused by the composer missing a deadline
+
+        /**
+         * Bitmask for jank due to deadlines missed by the composer.
+         */
         public static final int JANK_COMPOSER = 1 << 0;
-        // Jank caused by the application missing the composer's deadline
+
+        /**
+         * Bitmask for jank due to deadlines missed by the application.
+         */
         public static final int JANK_APPLICATION = 1 << 1;
-        // Jank due to other unknown reasons
+
+        /**
+         * Bitmask for jank due to deadlines missed by other system components.
+         */
         public static final int JANK_OTHER = 1 << 2;
 
+        private final long mFrameVsyncId;
+        private final @JankType int mJankType;
+        private final long mFrameIntervalNs;
+        private final long mScheduledAppFrameTimeNs;
+        private final long mActualAppFrameTimeNs;
+
+        /**
+         * @hide
+         */
         public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs,
                 long scheduledAppFrameTimeNs, long actualAppFrameTimeNs) {
-            this.frameVsyncId = frameVsyncId;
-            this.jankType = jankType;
-            this.frameIntervalNs = frameIntervalNs;
-            this.scheduledAppFrameTimeNs = scheduledAppFrameTimeNs;
-            this.actualAppFrameTimeNs = actualAppFrameTimeNs;
+            mFrameVsyncId = frameVsyncId;
+            mJankType = jankType;
+            mFrameIntervalNs = frameIntervalNs;
+            mScheduledAppFrameTimeNs = scheduledAppFrameTimeNs;
+            mActualAppFrameTimeNs = actualAppFrameTimeNs;
         }
 
-        public final long frameVsyncId;
-        public final @JankType int jankType;
-        public final long frameIntervalNs;
-        public final long scheduledAppFrameTimeNs;
-        public final long actualAppFrameTimeNs;
+        /**
+         * Returns the id of the frame for this jank classification.
+         *
+         * @see FrameMetrics#FRAME_TIMELINE_VSYNC_ID
+         * @see Choreographer.FrameTimeline#getVsyncId
+         * @see Transaction#setFrameTimeline
+         * @return the frame id
+         */
+        public long getVsyncId() {
+            return mFrameVsyncId;
+        }
+
+        /**
+         * Returns the bitmask indicating the types of jank observed.
+         *
+         * @return the jank type bitmask
+         */
+        public @JankType int getJankType() {
+            return mJankType;
+        }
+
+        /**
+         * Returns the time between frame VSyncs in nanoseconds.
+         *
+         * @return the frame interval in ns
+         * @hide
+         */
+        public long getFrameIntervalNanos() {
+            return mFrameIntervalNs;
+        }
+
+        /**
+         * Returns the duration in nanoseconds the application was scheduled to use to render this
+         * frame.
+         * <p>
+         * Note that this may be higher than the frame interval to allow for CPU/GPU
+         * parallelization of work.
+         *
+         * @return scheduled app time in ns
+         */
+        public long getScheduledAppFrameTimeNanos() {
+            return mScheduledAppFrameTimeNs;
+        }
+
+        /**
+         * Returns the actual time in nanoseconds taken by the application to render this frame.
+         *
+         * @return the actual app time in ns
+         */
+        public long getActualAppFrameTimeNanos() {
+            return mActualAppFrameTimeNs;
+        }
+
+        @Override
+        public String toString() {
+            return "JankData{vsync=" + mFrameVsyncId
+                    + ", jankType=0x" + Integer.toHexString(mJankType)
+                    + ", frameInterval=" + mFrameIntervalNs + "ns"
+                    + ", scheduledAppTime=" + mScheduledAppFrameTimeNs + "ns"
+                    + ", actualAppTime=" + mActualAppFrameTimeNs + "ns}";
+        }
     }
 
     /**
@@ -458,12 +546,13 @@
      * surface.
      *
      * @see JankData
-     * @see #addJankDataListener
-     * @hide
+     * @see #addOnJankDataListener
      */
+    @FlaggedApi(Flags.FLAG_JANK_API)
     public interface OnJankDataListener {
         /**
-         * Called when new jank classifications are available.
+         * Called when new jank classifications are available. The listener is invoked out of band
+         * of the rendered frames with jank classification data for a batch of frames.
          */
         void onJankDataAvailable(@NonNull List<JankData> jankData);
 
@@ -471,9 +560,22 @@
 
     /**
      * Handle to a registered {@link OnJankDatalistener}.
-     * @hide
      */
+    @FlaggedApi(Flags.FLAG_JANK_API)
     public static class OnJankDataListenerRegistration {
+        /** @hide */
+        public static final OnJankDataListenerRegistration NONE =
+                new OnJankDataListenerRegistration() {
+                    @Override
+                    public void flush() {}
+
+                    @Override
+                    public void removeAfter(long afterVsync) {}
+
+                    @Override
+                    public void release() {}
+                };
+
         private final long mNativeObject;
 
         private static final NativeAllocationRegistry sRegistry =
@@ -484,6 +586,11 @@
         private final Runnable mFreeNativeResources;
         private boolean mRemoved = false;
 
+        private OnJankDataListenerRegistration() {
+            mNativeObject = 0;
+            mFreeNativeResources = () -> {};
+        }
+
         OnJankDataListenerRegistration(SurfaceControl surface, OnJankDataListener listener) {
             mNativeObject = nativeCreateJankDataListenerWrapper(surface.mNativeObject, listener);
             mFreeNativeResources = (mNativeObject == 0) ? () -> {} :
@@ -499,10 +606,17 @@
         }
 
         /**
-         * Request the removal of the registered listener after the VSync with the provided ID. Use
-         * a value <= 0 for afterVsync to remove the listener immediately. The given listener will
-         * not be removed before the given VSync, but may still reveive data for frames past the
-         * provided VSync.
+         * Schedule the removal of the registered listener after the frame with the provided id.
+         * <p>
+         * Because jank classification is only possible after frames have been displayed, the
+         * callbacks are always delayed. To ensure receipt of all jank classification data, an
+         * application can schedule the removal to happen no sooner than after the data for the
+         * frame with the provided id has been provided.
+         * <p>
+         * Use a value &lt;= 0 for afterVsync to remove the listener immediately, ensuring no future
+         * callbacks.
+         *
+         * @param afterVsync the id of the Vsync after which to remove the listener
          */
         public void removeAfter(long afterVsync) {
             mRemoved = true;
@@ -511,6 +625,7 @@
 
         /**
          * Free the native resources associated with the listener registration.
+         * @hide
          */
         public void release() {
             if (!mRemoved) {
@@ -663,6 +778,13 @@
     public static final int CAN_OCCLUDE_PRESENTATION = 0x00001000;
 
     /**
+     * Indicates that the SurfaceControl should recover from buffer stuffing when
+     * possible. This is the case when the SurfaceControl is a ViewRootImpl.
+     * @hide
+     */
+    public static final int RECOVERABLE_FROM_BUFFER_STUFFING = 0x00002000;
+
+    /**
      * Surface creation flag: Creates a surface where color components are interpreted
      * as "non pre-multiplied" by their alpha channel. Of course this flag is
      * meaningless for surfaces without an alpha channel. By default
@@ -4444,14 +4566,31 @@
             return this;
         }
 
-        /** @hide */
+        /**
+         * Sets the Luts for the layer.
+         *
+         * <p> The function also allows to clear previously applied lut(s). To do this,
+         * set the displayluts to be either {@code nullptr} or
+         * an empty {@link android.hardware.DisplayLuts} instance.
+         *
+         * @param sc The SurfaceControl to update
+         *
+         * @param displayLuts The selected Lut(s)
+         *
+         * @return this
+         * @see DisplayLuts
+         */
+        @FlaggedApi(android.hardware.flags.Flags.FLAG_LUTS_API)
         public @NonNull Transaction setLuts(@NonNull SurfaceControl sc,
-                @NonNull DisplayLuts displayLuts) {
+                @Nullable DisplayLuts displayLuts) {
             checkPreconditions(sc);
-
-            nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
-                    displayLuts.getOffsets(), displayLuts.getLutDimensions(),
-                    displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+            if (displayLuts != null && displayLuts.valid()) {
+                nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
+                        displayLuts.getOffsets(), displayLuts.getLutDimensions(),
+                        displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+            } else {
+                nativeSetLuts(mNativeObject, sc.mNativeObject, null, null, null, null, null);
+            }
             return this;
         }
 
@@ -4867,6 +5006,23 @@
             nativeSetDesiredPresentTimeNanos(mNativeObject, desiredPresentTimeNanos);
             return this;
         }
+
+        /**
+         * Specifies that the SurfaceControl is a buffer producer that should recover from buffer
+         * stuffing, meaning that the SurfaceControl is a ViewRootImpl.
+         *
+         * @hide
+         */
+        @NonNull
+        public Transaction setRecoverableFromBufferStuffing(@NonNull SurfaceControl sc) {
+            if (bufferStuffingRecovery()) {
+                checkPreconditions(sc);
+                nativeSetFlags(mNativeObject, sc.mNativeObject, RECOVERABLE_FROM_BUFFER_STUFFING,
+                        RECOVERABLE_FROM_BUFFER_STUFFING);
+            }
+            return this;
+        }
+
         /**
          * Writes the transaction to parcel, clearing the transaction as if it had been applied so
          * it can be used to store future transactions. It's the responsibility of the parcel
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 75d2da1..19d3dc4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -140,6 +140,8 @@
 import android.animation.AnimationHandler;
 import android.animation.LayoutTransition;
 import android.annotation.AnyThread;
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -1250,7 +1252,6 @@
         mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName);
         mThread = Thread.currentThread();
         mLocation = new WindowLeaked(null);
-        mLocation.fillInStackTrace();
         mWidth = -1;
         mHeight = -1;
         mDirty = new Rect();
@@ -2515,6 +2516,11 @@
     public void notifyInsetsAnimationRunningStateChanged(boolean running) {
         if (sToolkitSetFrameRateReadOnlyFlagValue) {
             mInsetsAnimationRunning = running;
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                Trace.instant(Trace.TRACE_TAG_VIEW,
+                        TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)",
+                        Boolean.toString(running)));
+            }
         }
     }
 
@@ -2758,6 +2764,9 @@
         // Only call transferFrom if the surface has changed to prevent inc the generation ID and
         // causing EGL resources to be recreated.
         mSurface.transferFrom(blastSurface);
+
+        // Since the SurfaceControl is a VRI, indicate that it can recover from buffer stuffing.
+        mTransaction.setRecoverableFromBufferStuffing(mSurfaceControl).applyAsyncUnsafe();
     }
 
     private void setBoundsLayerCrop(Transaction t) {
@@ -11897,6 +11906,20 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API)
+    public SurfaceControl.OnJankDataListenerRegistration registerOnJankDataListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SurfaceControl.OnJankDataListener listener) {
+        SurfaceControl.OnJankDataListener wrapped = (data) ->
+                executor.execute(() -> listener.onJankDataAvailable(data));
+        return mSurfaceControl.addOnJankDataListener(wrapped);
+    }
+
+    /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
      */
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 1af9387..1be7f48 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
 
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
@@ -79,27 +80,24 @@
      * Key used for writing the type of the view that generated the virtual structure of its
      * children.
      *
-     * For example, if the virtual structure is generated by a webview, the value would be
+     * <p>For example, if the virtual structure is generated by a webview, the value would be
      * "WebView". If the virtual structure is generated by a compose view, then the value would be
      * "ComposeView". The value is of type String.
      *
-     * This value is added to mainly help with debugging purpose.
-     *
-     * @hide
+     * <p>This value is added to mainly help with debugging purpose.
      */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
     public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE =
             "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE";
 
-
     /**
      * Key used for specifying the version of the view that generated the virtual structure for
      * itself and its children
      *
-     * For example, if the virtual structure is generated by a webview of version "104.0.5112.69",
-     * then the value should be "104.0.5112.69"
-     *
-     * @hide
+     * <p>For example, if the virtual structure is generated by a webview of version
+     * "104.0.5112.69", then the value should be "104.0.5112.69"
      */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
     public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER =
             "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER";
 
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 6b60858..bd27778 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -15,6 +15,9 @@
  */
 package android.view.autofill;
 
+import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -111,12 +114,43 @@
         return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION);
     }
 
-    /** @hide */
+    /**
+     * Returns the assigned unique identifier of this AutofillID.
+     *
+     * See @link{android.view.View#getAutofillId()} for more information on
+     * how this is generated for native Views.
+     */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
     public int getViewId() {
         return mViewId;
     }
 
     /**
+     * Gets the virtual id. This is set if the view is a virtual view, most commonly set if the View
+     * is of {@link android.webkit.WebView}.
+     */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+    public int getAutofillVirtualId() {
+        return mVirtualIntId;
+    }
+
+    /** Checks whether this AutofillId represents a virtual view. */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+    public boolean isVirtual() {
+        return !isNonVirtual();
+    }
+
+    /**
+     * Checks if this node is generate as part of a {@link android.app.assist.AssistStructure}. This
+     * will usually return true if it should be used by an autofill service provider, and false
+     * otherwise.
+     */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
+    public boolean isInAutofillSession() {
+        return hasSession();
+    }
+
+    /**
      * Gets the virtual child id.
      *
      * <p>Should only be used on subsystems where such id is represented by an {@code int}
@@ -181,7 +215,12 @@
         return (mFlags & FLAG_HAS_SESSION) != 0;
     }
 
-    /** @hide */
+    /**
+     * Used to get the Session identifier associated with this AutofillId.
+     *
+     * @return a non-zero integer if {@link #isInAutofillSession()} returns true
+     */
+    @FlaggedApi(FLAG_AUTOFILL_W_METRICS)
     public int getSessionId() {
         return mSessionId;
     }
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index b180e58..ebda4d4 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -28,5 +28,5 @@
     namespace: "wear_frameworks"
     name: "dynamic_view_rotary_haptics_configuration"
     description: "Whether ScrollFeedbackProvider dynamically disables View-based rotary haptics."
-    bug: "377998870 "
+    bug: "377998870"
 }
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 1b86f96..3b6343e 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -132,4 +132,12 @@
     description: "Use refactored round scrollbar."
     bug: "333417898"
     is_fixed_read_only: true
+}
+
+flag {
+    name: "buffer_stuffing_recovery"
+    namespace: "window_surfaces"
+    description: "Recover from buffer stuffing when SurfaceFlinger misses a frame"
+    bug: "294922229"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index fb3e083..afe195c 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -24,6 +24,7 @@
 import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS;
 import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID;
 import static android.view.inputmethod.Flags.FLAG_EDITORINFO_HANDWRITING_ENABLED;
+import static android.view.inputmethod.Flags.FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO;
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -470,12 +471,10 @@
     public String packageName;
 
     /**
-     * Autofill Id for the field that's currently on focus.
-     *
-     * <p> Marked as hide since it's only used by framework.</p>
-     * @hide
+     * Autofill Id for the field that's currently on focus. See link {@link AutofillId} for more
+     * details. It is set by {@link View#getAutofillId()}
      */
-    public AutofillId autofillId;
+    private AutofillId autofillId;
 
     /**
      * Identifier for the editor's field.  This is optional, and may be
@@ -524,7 +523,6 @@
     @Nullable
     public LocaleList hintLocales = null;
 
-
     /**
      * List of acceptable MIME types for
      * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}.
@@ -759,6 +757,30 @@
         return mIsStylusHandwritingEnabled;
     }
 
+    private boolean mWritingToolsEnabled = true;
+
+    /**
+     * Returns {@code true} when an {@code Editor} has writing tools enabled.
+     * {@code true} by default for all editors. Toolkits can optionally disable them where not
+     * relevant e.g. passwords, number input, etc.
+     * @see #setWritingToolsEnabled(boolean)
+     */
+    @FlaggedApi(Flags.FLAG_WRITING_TOOLS)
+    public boolean isWritingToolsEnabled() {
+        return mWritingToolsEnabled;
+    }
+
+    /**
+     * Set {@code false} if {@code Editor} opts-out of writing tools, that enable IMEs to replace
+     * text with generative AI text.
+     * @param enabled set {@code true} to enabled or {@code false to disable} support.
+     * @see #isWritingToolsEnabled()
+     */
+    @FlaggedApi(Flags.FLAG_WRITING_TOOLS)
+    public void setWritingToolsEnabled(boolean enabled) {
+        mWritingToolsEnabled = enabled;
+    }
+
     /**
      * If not {@code null}, this editor needs to talk to IMEs that run for the specified user, no
      * matter what user ID the calling process has.
@@ -1200,6 +1222,28 @@
     }
 
     /**
+     * Returns the {@link AutofillId} of the view that this {@link EditorInfo} is associated with.
+     * The value is filled in with the result of {@link android.view.View#getAutofillId()
+     * View.getAutofillId()} on the view that is being edited.
+     *
+     * Note: For virtual view(e.g. Compose or Webview), default behavior is the autofillId is the id
+     * of the container view, unless the virtual view provider sets the virtual id when the
+     * InputMethodManager calls {@link android.view.View#onCreateInputConnection()} on the container
+     * view.
+     */
+    @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO)
+    @Nullable
+    public AutofillId getAutofillId() {
+        return autofillId;
+    }
+
+    /** Sets the {@link AutofillId} of the view that this {@link EditorInfo} is associated with. */
+    @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO)
+    public void setAutofillId(@Nullable AutofillId autofillId) {
+        this.autofillId = autofillId;
+    }
+
+    /**
      * Export the state of {@link EditorInfo} into a protocol buffer output stream.
      *
      * @param proto Stream to write the state to
@@ -1255,6 +1299,7 @@
                 + InputMethodDebug.handwritingGestureTypeFlagsToString(
                         mSupportedHandwritingGesturePreviewTypes));
         pw.println(prefix + "isStylusHandwritingEnabled=" + mIsStylusHandwritingEnabled);
+        pw.println(prefix + "writingToolsEnabled=" + mWritingToolsEnabled);
         pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
         if (targetInputMethodUser != null) {
             pw.println(prefix + "targetInputMethodUserId=" + targetInputMethodUser.getIdentifier());
@@ -1335,6 +1380,7 @@
         }
         dest.writeStringArray(contentMimeTypes);
         UserHandle.writeToParcel(targetInputMethodUser, dest);
+        dest.writeBoolean(mWritingToolsEnabled);
     }
 
     /**
@@ -1375,6 +1421,7 @@
                     res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
                     res.contentMimeTypes = source.readStringArray();
                     res.targetInputMethodUser = UserHandle.readFromParcel(source);
+                    res.mWritingToolsEnabled = source.readBoolean();
                     return res;
                 }
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6026e60..6303c76 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -5179,7 +5179,7 @@
         // system can verify the consistency between the uid of this process and package name passed
         // from here. See comment of Context#getOpPackageName() for details.
         editorInfo.packageName = servedView.getContext().getOpPackageName();
-        editorInfo.autofillId = servedView.getAutofillId();
+        editorInfo.setAutofillId(servedView.getAutofillId());
         editorInfo.fieldId = servedView.getId();
         final InputConnection ic = servedView.onCreateInputConnection(editorInfo);
         if (DEBUG) Log.v(TAG, "Starting input: editorInfo=" + editorInfo + " ic=" + ic);
@@ -5188,7 +5188,7 @@
         // This ensures that even disconnected EditorInfos have well-defined attributes,
         // making them consistently and straightforwardly comparable.
         if (ic == null) {
-            editorInfo.autofillId = AutofillId.NO_AUTOFILL_ID;
+            editorInfo.setAutofillId(AutofillId.NO_AUTOFILL_ID);
             editorInfo.fieldId = 0;
         }
         return new Pair<>(ic, editorInfo);
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index edd9d6c..deaf957 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -165,4 +165,22 @@
     description: "Writing tools API"
     bug: "373788889"
     is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+  name: "public_autofill_id_in_editorinfo"
+  is_exported: true
+  namespace: "input_method"
+  description: "Guarding public API autofillId in editor info"
+  bug: "342672560"
+  is_fixed_read_only: true
+}
+
+flag {
+  name: "adaptive_handwriting_bounds"
+  is_exported: true
+  namespace: "input_method"
+  description: "Feature flag for adaptively increasing handwriting bounds."
+  bug: "350047836"
+  is_fixed_read_only: true
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d7750bd..cb70466 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -106,6 +106,7 @@
 import android.os.ParcelableParcel;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.BoringLayout;
@@ -9229,174 +9230,179 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        restartMarqueeIfNeeded();
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onDraw");
+        try {
+            restartMarqueeIfNeeded();
 
-        // Draw the background for this view
-        super.onDraw(canvas);
+            // Draw the background for this view
+            super.onDraw(canvas);
 
-        final int compoundPaddingLeft = getCompoundPaddingLeft();
-        final int compoundPaddingTop = getCompoundPaddingTop();
-        final int compoundPaddingRight = getCompoundPaddingRight();
-        final int compoundPaddingBottom = getCompoundPaddingBottom();
-        final int scrollX = mScrollX;
-        final int scrollY = mScrollY;
-        final int right = mRight;
-        final int left = mLeft;
-        final int bottom = mBottom;
-        final int top = mTop;
-        final boolean isLayoutRtl = isLayoutRtl();
-        final int offset = getHorizontalOffsetForDrawables();
-        final int leftOffset = isLayoutRtl ? 0 : offset;
-        final int rightOffset = isLayoutRtl ? offset : 0;
+            final int compoundPaddingLeft = getCompoundPaddingLeft();
+            final int compoundPaddingTop = getCompoundPaddingTop();
+            final int compoundPaddingRight = getCompoundPaddingRight();
+            final int compoundPaddingBottom = getCompoundPaddingBottom();
+            final int scrollX = mScrollX;
+            final int scrollY = mScrollY;
+            final int right = mRight;
+            final int left = mLeft;
+            final int bottom = mBottom;
+            final int top = mTop;
+            final boolean isLayoutRtl = isLayoutRtl();
+            final int offset = getHorizontalOffsetForDrawables();
+            final int leftOffset = isLayoutRtl ? 0 : offset;
+            final int rightOffset = isLayoutRtl ? offset : 0;
 
-        final Drawables dr = mDrawables;
-        if (dr != null) {
-            /*
-             * Compound, not extended, because the icon is not clipped
-             * if the text height is smaller.
-             */
+            final Drawables dr = mDrawables;
+            if (dr != null) {
+                /*
+                 * Compound, not extended, because the icon is not clipped
+                 * if the text height is smaller.
+                 */
 
-            int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
-            int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
+                int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
+                int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
 
-            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-            // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mShowing[Drawables.LEFT] != null) {
-                canvas.save();
-                canvas.translate(scrollX + mPaddingLeft + leftOffset,
-                        scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
-                dr.mShowing[Drawables.LEFT].draw(canvas);
-                canvas.restore();
+                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+                // Make sure to update invalidateDrawable() when changing this code.
+                if (dr.mShowing[Drawables.LEFT] != null) {
+                    canvas.save();
+                    canvas.translate(scrollX + mPaddingLeft + leftOffset,
+                            scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2);
+                    dr.mShowing[Drawables.LEFT].draw(canvas);
+                    canvas.restore();
+                }
+
+                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+                // Make sure to update invalidateDrawable() when changing this code.
+                if (dr.mShowing[Drawables.RIGHT] != null) {
+                    canvas.save();
+                    canvas.translate(scrollX + right - left - mPaddingRight
+                                    - dr.mDrawableSizeRight - rightOffset,
+                            scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
+                    dr.mShowing[Drawables.RIGHT].draw(canvas);
+                    canvas.restore();
+                }
+
+                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+                // Make sure to update invalidateDrawable() when changing this code.
+                if (dr.mShowing[Drawables.TOP] != null) {
+                    canvas.save();
+                    canvas.translate(scrollX + compoundPaddingLeft
+                            + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
+                    dr.mShowing[Drawables.TOP].draw(canvas);
+                    canvas.restore();
+                }
+
+                // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
+                // Make sure to update invalidateDrawable() when changing this code.
+                if (dr.mShowing[Drawables.BOTTOM] != null) {
+                    canvas.save();
+                    canvas.translate(scrollX + compoundPaddingLeft
+                                    + (hspace - dr.mDrawableWidthBottom) / 2,
+                            scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
+                    dr.mShowing[Drawables.BOTTOM].draw(canvas);
+                    canvas.restore();
+                }
             }
 
-            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-            // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mShowing[Drawables.RIGHT] != null) {
-                canvas.save();
-                canvas.translate(scrollX + right - left - mPaddingRight
-                        - dr.mDrawableSizeRight - rightOffset,
-                         scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
-                dr.mShowing[Drawables.RIGHT].draw(canvas);
-                canvas.restore();
+            int color = mCurTextColor;
+
+            if (mLayout == null) {
+                assumeLayout();
             }
 
-            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-            // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mShowing[Drawables.TOP] != null) {
-                canvas.save();
-                canvas.translate(scrollX + compoundPaddingLeft
-                        + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
-                dr.mShowing[Drawables.TOP].draw(canvas);
-                canvas.restore();
+            Layout layout = mLayout;
+
+            if (mHint != null && !mHideHint && mText.length() == 0) {
+                if (mHintTextColor != null) {
+                    color = mCurHintTextColor;
+                }
+
+                layout = mHintLayout;
             }
 
-            // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
-            // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mShowing[Drawables.BOTTOM] != null) {
-                canvas.save();
-                canvas.translate(scrollX + compoundPaddingLeft
-                        + (hspace - dr.mDrawableWidthBottom) / 2,
-                         scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
-                dr.mShowing[Drawables.BOTTOM].draw(canvas);
-                canvas.restore();
-            }
-        }
+            mTextPaint.setColor(color);
+            mTextPaint.drawableState = getDrawableState();
 
-        int color = mCurTextColor;
+            canvas.save();
+            /*  Would be faster if we didn't have to do this. Can we chop the
+                (displayable) text so that we don't need to do this ever?
+            */
 
-        if (mLayout == null) {
-            assumeLayout();
-        }
+            int extendedPaddingTop = getExtendedPaddingTop();
+            int extendedPaddingBottom = getExtendedPaddingBottom();
 
-        Layout layout = mLayout;
+            final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
+            final int maxScrollY = mLayout.getHeight() - vspace;
 
-        if (mHint != null && !mHideHint && mText.length() == 0) {
-            if (mHintTextColor != null) {
-                color = mCurHintTextColor;
+            float clipLeft = compoundPaddingLeft + scrollX;
+            float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
+            float clipRight = right - left - getCompoundPaddingRight() + scrollX;
+            float clipBottom = bottom - top + scrollY
+                    - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
+
+            if (mShadowRadius != 0) {
+                clipLeft += Math.min(0, mShadowDx - mShadowRadius);
+                clipRight += Math.max(0, mShadowDx + mShadowRadius);
+
+                clipTop += Math.min(0, mShadowDy - mShadowRadius);
+                clipBottom += Math.max(0, mShadowDy + mShadowRadius);
             }
 
-            layout = mHintLayout;
-        }
+            canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
 
-        mTextPaint.setColor(color);
-        mTextPaint.drawableState = getDrawableState();
+            int voffsetText = 0;
+            int voffsetCursor = 0;
 
-        canvas.save();
-        /*  Would be faster if we didn't have to do this. Can we chop the
-            (displayable) text so that we don't need to do this ever?
-        */
+            // translate in by our padding
+            /* shortcircuit calling getVerticaOffset() */
+            if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
+                voffsetText = getVerticalOffset(false);
+                voffsetCursor = getVerticalOffset(true);
+            }
+            canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
 
-        int extendedPaddingTop = getExtendedPaddingTop();
-        int extendedPaddingBottom = getExtendedPaddingBottom();
+            final int layoutDirection = getLayoutDirection();
+            final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+            if (isMarqueeFadeEnabled()) {
+                if (!mSingleLine && getLineCount() == 1 && canMarquee()
+                        && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
+                    final int width = mRight - mLeft;
+                    final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
+                    final float dx = mLayout.getLineRight(0) - (width - padding);
+                    canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+                }
 
-        final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
-        final int maxScrollY = mLayout.getHeight() - vspace;
+                if (mMarquee != null && mMarquee.isRunning()) {
+                    final float dx = -mMarquee.getScroll();
+                    canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+                }
+            }
 
-        float clipLeft = compoundPaddingLeft + scrollX;
-        float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
-        float clipRight = right - left - getCompoundPaddingRight() + scrollX;
-        float clipBottom = bottom - top + scrollY
-                - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
+            final int cursorOffsetVertical = voffsetCursor - voffsetText;
 
-        if (mShadowRadius != 0) {
-            clipLeft += Math.min(0, mShadowDx - mShadowRadius);
-            clipRight += Math.max(0, mShadowDx + mShadowRadius);
+            maybeUpdateHighlightPaths();
+            // If there is a gesture preview highlight, then the selection or cursor is not drawn.
+            Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
+            if (mEditor != null) {
+                mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
+                        mHighlightPaint, cursorOffsetVertical);
+            } else {
+                layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                        cursorOffsetVertical);
+            }
 
-            clipTop += Math.min(0, mShadowDy - mShadowRadius);
-            clipBottom += Math.max(0, mShadowDy + mShadowRadius);
-        }
-
-        canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
-
-        int voffsetText = 0;
-        int voffsetCursor = 0;
-
-        // translate in by our padding
-        /* shortcircuit calling getVerticaOffset() */
-        if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) {
-            voffsetText = getVerticalOffset(false);
-            voffsetCursor = getVerticalOffset(true);
-        }
-        canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText);
-
-        final int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-        if (isMarqueeFadeEnabled()) {
-            if (!mSingleLine && getLineCount() == 1 && canMarquee()
-                    && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
-                final int width = mRight - mLeft;
-                final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
-                final float dx = mLayout.getLineRight(0) - (width - padding);
+            if (mMarquee != null && mMarquee.shouldDrawGhost()) {
+                final float dx = mMarquee.getGhostOffset();
                 canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
+                layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                        cursorOffsetVertical);
             }
 
-            if (mMarquee != null && mMarquee.isRunning()) {
-                final float dx = -mMarquee.getScroll();
-                canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-            }
+            canvas.restore();
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
-
-        final int cursorOffsetVertical = voffsetCursor - voffsetText;
-
-        maybeUpdateHighlightPaths();
-        // If there is a gesture preview highlight, then the selection or cursor is not drawn.
-        Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
-        if (mEditor != null) {
-            mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
-                    mHighlightPaint, cursorOffsetVertical);
-        } else {
-            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
-                    cursorOffsetVertical);
-        }
-
-        if (mMarquee != null && mMarquee.shouldDrawGhost()) {
-            final float dx = mMarquee.getGhostOffset();
-            canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
-                    cursorOffsetVertical);
-        }
-
-        canvas.restore();
     }
 
     @Override
@@ -11254,192 +11260,201 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onMeasure");
+        try {
+            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
 
-        int width;
-        int height;
+            int width;
+            int height;
 
-        BoringLayout.Metrics boring = UNKNOWN_BORING;
-        BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
+            BoringLayout.Metrics boring = UNKNOWN_BORING;
+            BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
 
-        if (mTextDir == null) {
-            mTextDir = getTextDirectionHeuristic();
-        }
-
-        int des = -1;
-        boolean fromexisting = false;
-        final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
-                ?  (float) widthSize : Float.MAX_VALUE;
-
-        if (widthMode == MeasureSpec.EXACTLY) {
-            // Parent has told us how big to be. So be it.
-            width = widthSize;
-        } else {
-            if (mLayout != null && mEllipsize == null) {
-                des = desired(mLayout, mUseBoundsForWidth);
+            if (mTextDir == null) {
+                mTextDir = getTextDirectionHeuristic();
             }
 
-            if (des < 0) {
-                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
-                        isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
-                        mBoring);
-                if (boring != null) {
-                    mBoring = boring;
-                }
+            int des = -1;
+            boolean fromexisting = false;
+            final float widthLimit = (widthMode == MeasureSpec.AT_MOST)
+                    ? (float) widthSize : Float.MAX_VALUE;
+
+            if (widthMode == MeasureSpec.EXACTLY) {
+                // Parent has told us how big to be. So be it.
+                width = widthSize;
             } else {
-                fromexisting = true;
-            }
+                if (mLayout != null && mEllipsize == null) {
+                    des = desired(mLayout, mUseBoundsForWidth);
+                }
 
-            if (boring == null || boring == UNKNOWN_BORING) {
                 if (des < 0) {
-                    des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
-                            mTransformed.length(), mTextPaint, mTextDir, widthLimit,
-                            mUseBoundsForWidth));
-                }
-                width = des;
-            } else {
-                if (mUseBoundsForWidth) {
-                    RectF bbox = boring.getDrawingBoundingBox();
-                    float rightMax = Math.max(bbox.right, boring.width);
-                    float leftMin = Math.min(bbox.left, 0);
-                    width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
-                } else {
-                    width = boring.width;
-                }
-            }
-
-            final Drawables dr = mDrawables;
-            if (dr != null) {
-                width = Math.max(width, dr.mDrawableWidthTop);
-                width = Math.max(width, dr.mDrawableWidthBottom);
-            }
-
-            if (mHint != null) {
-                int hintDes = -1;
-                int hintWidth;
-
-                if (mHintLayout != null && mEllipsize == null) {
-                    hintDes = desired(mHintLayout, mUseBoundsForWidth);
-                }
-
-                if (hintDes < 0) {
-                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+                    boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
                             isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
-                            mHintBoring);
-                    if (hintBoring != null) {
-                        mHintBoring = hintBoring;
+                            mBoring);
+                    if (boring != null) {
+                        mBoring = boring;
                     }
+                } else {
+                    fromexisting = true;
                 }
 
-                if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
-                    if (hintDes < 0) {
-                        hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
-                                mHint.length(), mTextPaint, mTextDir, widthLimit,
+                if (boring == null || boring == UNKNOWN_BORING) {
+                    if (des < 0) {
+                        des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
+                                mTransformed.length(), mTextPaint, mTextDir, widthLimit,
                                 mUseBoundsForWidth));
                     }
-                    hintWidth = hintDes;
+                    width = des;
                 } else {
-                    hintWidth = hintBoring.width;
+                    if (mUseBoundsForWidth) {
+                        RectF bbox = boring.getDrawingBoundingBox();
+                        float rightMax = Math.max(bbox.right, boring.width);
+                        float leftMin = Math.min(bbox.left, 0);
+                        width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin));
+                    } else {
+                        width = boring.width;
+                    }
                 }
 
-                if (hintWidth > width) {
-                    width = hintWidth;
+                final Drawables dr = mDrawables;
+                if (dr != null) {
+                    width = Math.max(width, dr.mDrawableWidthTop);
+                    width = Math.max(width, dr.mDrawableWidthBottom);
                 }
-            }
 
-            width += getCompoundPaddingLeft() + getCompoundPaddingRight();
+                if (mHint != null) {
+                    int hintDes = -1;
+                    int hintWidth;
 
-            if (mMaxWidthMode == EMS) {
-                width = Math.min(width, mMaxWidth * getLineHeight());
-            } else {
-                width = Math.min(width, mMaxWidth);
-            }
+                    if (mHintLayout != null && mEllipsize == null) {
+                        hintDes = desired(mHintLayout, mUseBoundsForWidth);
+                    }
 
-            if (mMinWidthMode == EMS) {
-                width = Math.max(width, mMinWidth * getLineHeight());
-            } else {
-                width = Math.max(width, mMinWidth);
-            }
+                    if (hintDes < 0) {
+                        hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
+                                isFallbackLineSpacingForBoringLayout(),
+                                getResolvedMinimumFontMetrics(),
+                                mHintBoring);
+                        if (hintBoring != null) {
+                            mHintBoring = hintBoring;
+                        }
+                    }
 
-            // Check against our minimum width
-            width = Math.max(width, getSuggestedMinimumWidth());
+                    if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
+                        if (hintDes < 0) {
+                            hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
+                                    mHint.length(), mTextPaint, mTextDir, widthLimit,
+                                    mUseBoundsForWidth));
+                        }
+                        hintWidth = hintDes;
+                    } else {
+                        hintWidth = hintBoring.width;
+                    }
 
-            if (widthMode == MeasureSpec.AT_MOST) {
-                width = Math.min(widthSize, width);
-            }
-        }
+                    if (hintWidth > width) {
+                        width = hintWidth;
+                    }
+                }
 
-        int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
-        int unpaddedWidth = want;
+                width += getCompoundPaddingLeft() + getCompoundPaddingRight();
 
-        if (mHorizontallyScrolling) want = VERY_WIDE;
-
-        int hintWant = want;
-        int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
-
-        if (mLayout == null) {
-            makeNewLayout(want, hintWant, boring, hintBoring,
-                          width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
-        } else {
-            final boolean layoutChanged = (mLayout.getWidth() != want) || (hintWidth != hintWant)
-                    || (mLayout.getEllipsizedWidth()
-                            != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
-
-            final boolean widthChanged = (mHint == null) && (mEllipsize == null)
-                    && (want > mLayout.getWidth())
-                    && (mLayout instanceof BoringLayout
-                            || (fromexisting && des >= 0 && des <= want));
-
-            final boolean maximumChanged = (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
-
-            if (layoutChanged || maximumChanged) {
-                if (!maximumChanged && widthChanged) {
-                    mLayout.increaseWidthTo(want);
+                if (mMaxWidthMode == EMS) {
+                    width = Math.min(width, mMaxWidth * getLineHeight());
                 } else {
-                    makeNewLayout(want, hintWant, boring, hintBoring,
-                            width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
+                    width = Math.min(width, mMaxWidth);
                 }
+
+                if (mMinWidthMode == EMS) {
+                    width = Math.max(width, mMinWidth * getLineHeight());
+                } else {
+                    width = Math.max(width, mMinWidth);
+                }
+
+                // Check against our minimum width
+                width = Math.max(width, getSuggestedMinimumWidth());
+
+                if (widthMode == MeasureSpec.AT_MOST) {
+                    width = Math.min(widthSize, width);
+                }
+            }
+
+            int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight();
+            int unpaddedWidth = want;
+
+            if (mHorizontallyScrolling) want = VERY_WIDE;
+
+            int hintWant = want;
+            int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth();
+
+            if (mLayout == null) {
+                makeNewLayout(want, hintWant, boring, hintBoring,
+                        width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
             } else {
-                // Nothing has changed
+                final boolean layoutChanged =
+                        (mLayout.getWidth() != want) || (hintWidth != hintWant)
+                                || (mLayout.getEllipsizedWidth()
+                                != width - getCompoundPaddingLeft() - getCompoundPaddingRight());
+
+                final boolean widthChanged = (mHint == null) && (mEllipsize == null)
+                        && (want > mLayout.getWidth())
+                        && (mLayout instanceof BoringLayout
+                        || (fromexisting && des >= 0 && des <= want));
+
+                final boolean maximumChanged =
+                        (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum);
+
+                if (layoutChanged || maximumChanged) {
+                    if (!maximumChanged && widthChanged) {
+                        mLayout.increaseWidthTo(want);
+                    } else {
+                        makeNewLayout(want, hintWant, boring, hintBoring,
+                                width - getCompoundPaddingLeft() - getCompoundPaddingRight(),
+                                false);
+                    }
+                } else {
+                    // Nothing has changed
+                }
             }
-        }
 
-        if (heightMode == MeasureSpec.EXACTLY) {
-            // Parent has told us how big to be. So be it.
-            height = heightSize;
-            mDesiredHeightAtMeasure = -1;
-        } else {
-            int desired = getDesiredHeight();
+            if (heightMode == MeasureSpec.EXACTLY) {
+                // Parent has told us how big to be. So be it.
+                height = heightSize;
+                mDesiredHeightAtMeasure = -1;
+            } else {
+                int desired = getDesiredHeight();
 
-            height = desired;
-            mDesiredHeightAtMeasure = desired;
+                height = desired;
+                mDesiredHeightAtMeasure = desired;
 
-            if (heightMode == MeasureSpec.AT_MOST) {
-                height = Math.min(desired, heightSize);
+                if (heightMode == MeasureSpec.AT_MOST) {
+                    height = Math.min(desired, heightSize);
+                }
             }
-        }
 
-        int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
-        if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
-            unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
-        }
+            int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom();
+            if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
+                unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
+            }
 
-        /*
-         * We didn't let makeNewLayout() register to bring the cursor into view,
-         * so do it here if there is any possibility that it is needed.
-         */
-        if (mMovement != null
-                || mLayout.getWidth() > unpaddedWidth
-                || mLayout.getHeight() > unpaddedHeight) {
-            registerForPreDraw();
-        } else {
-            scrollTo(0, 0);
-        }
+            /*
+             * We didn't let makeNewLayout() register to bring the cursor into view,
+             * so do it here if there is any possibility that it is needed.
+             */
+            if (mMovement != null
+                    || mLayout.getWidth() > unpaddedWidth
+                    || mLayout.getHeight() > unpaddedHeight) {
+                registerForPreDraw();
+            } else {
+                scrollTo(0, 0);
+            }
 
-        setMeasuredDimension(width, height);
+            setMeasuredDimension(width, height);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
     }
 
     /**
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 0f2dd10..2c21417 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -49,6 +49,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
+import android.os.BinderProxy;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1089,8 +1090,13 @@
         @Override
         public String toString() {
             final StringBuilder sb = new StringBuilder();
-            sb.append('{'); sb.append(mContainer);
-            sb.append(" m="); sb.append(modeToString(mMode));
+            sb.append('{');
+            if (mContainer != null && !(mContainer.asBinder() instanceof BinderProxy)) {
+                // Only log the token if it is not a binder proxy and has additional container info
+                sb.append(mContainer);
+                sb.append(" ");
+            }
+            sb.append("m="); sb.append(modeToString(mMode));
             sb.append(" f="); sb.append(flagsToString(mFlags));
             if (mParent != null) {
                 sb.append(" p="); sb.append(mParent);
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 3fe63ab..a88a172 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -1120,8 +1120,8 @@
     @NonNull
     public String toString() {
         return "WindowContainerTransaction {"
-                + " changes = " + mChanges
-                + " hops = " + mHierarchyOps
+                + " changes= " + mChanges
+                + " hops= " + mHierarchyOps
                 + " errorCallbackToken=" + mErrorCallbackToken
                 + " taskFragmentOrganizer=" + mTaskFragmentOrganizer
                 + " }";
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index f474b34..eebdeadc 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -402,4 +402,11 @@
     namespace: "lse_desktop_experience"
     description: "Enables HSUM on desktop mode."
     bug: "366397912"
+}
+
+flag {
+    name: "enable_multiple_desktops"
+    namespace: "lse_desktop_experience"
+    description: "Enable multiple desktop sessions for desktop windowing."
+    bug: "379158791"
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 392c307..96b9dc7 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -97,3 +97,12 @@
     is_fixed_read_only: true
     bug: "308662081"
 }
+
+flag {
+    name: "jank_api"
+    namespace: "window_surfaces"
+    description: "Adds the jank data listener to AttachedSurfaceControl"
+    is_fixed_read_only: true
+    is_exported: true
+    bug: "293949943"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 4f924a82..ff69610 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -418,6 +418,17 @@
 }
 
 flag {
+  name: "record_task_snapshots_before_shutdown"
+  namespace: "windowing_frontend"
+  description: "Record task snapshots before shutdown"
+  bug: "376821232"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "predictive_back_three_button_nav"
     namespace: "systemui"
     description: "Enable Predictive Back Animation for 3-button-nav"
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index a21a842..543adac 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -257,7 +257,6 @@
                         if (VALIDATE_TIMES) {
                             if (mActiveDuration > mAssociationState.mTotalActiveDuration) {
                                 RuntimeException ex = new RuntimeException();
-                                ex.fillInStackTrace();
                                 Slog.w(TAG, "Source act duration " + mActiveDurations
                                         + " exceeds total " + mAssociationState.mTotalActiveDuration
                                         + " in procstate " + mActiveProcState + " in source "
@@ -650,7 +649,6 @@
                         + mySrc.mKey.mProcess + " to assoc " + mName);
                 if ((mySrc.mDuration + otherSrc.mDuration) > mTotalDuration) {
                     RuntimeException ex = new RuntimeException();
-                    ex.fillInStackTrace();
                     Slog.w(TAG, "Source tot duration " + mySrc.mDuration + "+"
                             + otherSrc.mDuration
                             + (newSrc ? " (new)" : " (old)") + " exceeds total "
@@ -665,7 +663,6 @@
                             + mySrc.mKey.mProcess + " to assoc " + mName);
                     if ((mySrc.mActiveDuration + otherSrc.mActiveDuration) > mTotalDuration) {
                         RuntimeException ex = new RuntimeException();
-                        ex.fillInStackTrace();
                         Slog.w(TAG, "Source act duration " + mySrc.mActiveDuration + "+"
                                 + otherSrc.mActiveDuration
                                 + (newSrc ? " (new)" : " (old)") + " exceeds total "
@@ -746,14 +743,12 @@
             if (VALIDATE_TIMES) {
                 if (src.mDuration > mTotalDuration) {
                     RuntimeException ex = new RuntimeException();
-                    ex.fillInStackTrace();
                     Slog.w(TAG, "Reading tot duration " + src.mDuration
                             + " exceeds total " + mTotalDuration + " in source "
                             + src.mKey.mProcess + " to assoc " + mName, ex);
                 }
                 if (src.mActiveDurations == null && src.mActiveDuration > mTotalDuration) {
                     RuntimeException ex = new RuntimeException();
-                    ex.fillInStackTrace();
                     Slog.w(TAG, "Reading act duration " + src.mActiveDuration
                             + " exceeds total " + mTotalDuration + " in source "
                             + src.mKey.mProcess + " to assoc " + mName, ex);
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 0dbdb36..7523a2d 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -538,7 +538,6 @@
     public void incActiveServices(String serviceName) {
         if (DEBUG && "".equals(mName)) {
             RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
             Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
                     + " to " + (mNumActiveServices+1), here);
         }
@@ -551,7 +550,6 @@
     public void decActiveServices(String serviceName) {
         if (DEBUG && "".equals(mName)) {
             RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
                     + " to " + (mNumActiveServices-1), here);
         }
@@ -569,7 +567,6 @@
     public void incStartedServices(int memFactor, long now, String serviceName) {
         if (false) {
             RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
             Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
                     + " to " + (mNumStartedServices+1), here);
         }
@@ -585,7 +582,6 @@
     public void decStartedServices(int memFactor, long now, String serviceName) {
         if (false) {
             RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
                     + " to " + (mNumStartedServices-1), here);
         }
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 21c7baa..469ab48 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -410,4 +410,15 @@
      * however backups initiated by the framework will call this method to retrieve one.
      */
     void getBackupManagerMonitor(in AndroidFuture<IBackupManagerMonitor> resultFuture);
+
+    /**
+     * Ask the transport whether packages that are about to be backed up or restored should not be
+     * put into a restricted mode by the framework and started normally instead. The
+     * {@code resultFuture} should be completed with a subset of the packages passed in, indicating
+     * which packages should NOT be put into restricted mode for the given operation type.
+     *
+     * @param operationType 0 for backup, 1 for restore.
+     */
+    void getPackagesThatShouldNotUseRestrictedMode(in List<String> packageNames, int operationType,
+            in AndroidFuture<List<String>> resultFuture);
 }
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 44c0bd0..2834e68 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -139,7 +139,7 @@
         }
 
         static JankInfo createFromSurfaceControlCallback(SurfaceControl.JankData jankStat) {
-            return new JankInfo(jankStat.frameVsyncId).update(jankStat);
+            return new JankInfo(jankStat.getVsyncId()).update(jankStat);
         }
 
         private JankInfo(long frameVsyncId) {
@@ -154,10 +154,10 @@
 
         private JankInfo update(SurfaceControl.JankData jankStat) {
             this.surfaceControlCallbackFired = true;
-            this.jankType = jankStat.jankType;
-            this.refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.frameIntervalNs);
+            this.jankType = jankStat.getJankType();
+            this.refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.getFrameIntervalNanos());
             if (Flags.useSfFrameDuration()) {
-                this.totalDurationNanos = jankStat.actualAppFrameTimeNs;
+                this.totalDurationNanos = jankStat.getActualAppFrameTimeNanos();
             }
             return this;
         }
@@ -458,14 +458,14 @@
                 }
 
                 for (SurfaceControl.JankData jankStat : jankData) {
-                    if (!isInRange(jankStat.frameVsyncId)) {
+                    if (!isInRange(jankStat.getVsyncId())) {
                         continue;
                     }
-                    JankInfo info = findJankInfo(jankStat.frameVsyncId);
+                    JankInfo info = findJankInfo(jankStat.getVsyncId());
                     if (info != null) {
                         info.update(jankStat);
                     } else {
-                        mJankInfos.put((int) jankStat.frameVsyncId,
+                        mJankInfos.put((int) jankStat.getVsyncId(),
                                 JankInfo.createFromSurfaceControlCallback(jankStat));
                     }
                 }
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 6b6b81f..48d0d6c 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -410,6 +410,11 @@
     private int mLocaleConfigRes;
     private boolean mAllowCrossUidActivitySwitchFromBelow;
 
+    @Nullable
+    private int[] mAlternateLauncherIconResIds;
+    @Nullable
+    private int[] mAlternateLauncherLabelResIds;
+
     private List<AndroidPackageSplit> mSplits;
 
     @NonNull
@@ -874,6 +879,18 @@
         return adoptPermissions;
     }
 
+    @Nullable
+    @Override
+    public int[] getAlternateLauncherIconResIds() {
+        return mAlternateLauncherIconResIds;
+    }
+
+    @Nullable
+    @Override
+    public int[] getAlternateLauncherLabelResIds() {
+        return mAlternateLauncherLabelResIds;
+    }
+
     @NonNull
     @Override
     public List<ParsedApexSystemService> getApexSystemServices() {
@@ -1888,6 +1905,19 @@
     }
 
     @Override
+    public PackageImpl setAlternateLauncherIconResIds(@Nullable int[] alternateLauncherIconResIds) {
+        this.mAlternateLauncherIconResIds = alternateLauncherIconResIds;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAlternateLauncherLabelResIds(
+            @Nullable int[] alternateLauncherLabelResIds) {
+        this.mAlternateLauncherLabelResIds = alternateLauncherLabelResIds;
+        return this;
+    }
+
+    @Override
     public PackageImpl setTaskReparentingAllowed(boolean value) {
         return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value);
     }
@@ -3273,6 +3303,8 @@
         dest.writeLong(this.mBooleans2);
         dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
         dest.writeInt(this.mIntentMatchingFlags);
+        dest.writeIntArray(this.mAlternateLauncherIconResIds);
+        dest.writeIntArray(this.mAlternateLauncherLabelResIds);
     }
 
     private void writeFeatureFlagState(@NonNull Parcel dest) {
@@ -3465,6 +3497,8 @@
         this.mBooleans2 = in.readLong();
         this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
         this.mIntentMatchingFlags = in.readInt();
+        this.mAlternateLauncherIconResIds = in.createIntArray();
+        this.mAlternateLauncherLabelResIds = in.createIntArray();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index f4bceb8..67b985a 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -413,6 +413,18 @@
 
     ParsingPackage setOnBackInvokedCallbackEnabled(boolean enableOnBackInvokedCallback);
 
+    /**
+     * Set the drawable resources id array of the alternate icons that are parsing from the
+     * AndroidManifest file
+     */
+    ParsingPackage setAlternateLauncherIconResIds(int[] alternateLauncherIconResIds);
+
+    /**
+     * Set the string resources id array of the alternate labels that are parsing from the
+     * AndroidManifest file
+     */
+    ParsingPackage setAlternateLauncherLabelResIds(int[] alternateLauncherLabelResIds);
+
     @CallSuper
     ParsedPackage hideAsParsed();
 
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 5db7b41..8a6e6be 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
@@ -154,6 +155,13 @@
 
     private static final String TAG = ParsingUtils.TAG;
 
+    // It is the maximum length of the typedArray of {@link android.R.attr#alternateIcons}
+    // and {@link android.R.attr#alternateLabels}.
+    private static final int MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH = 500;
+
+    private static final String TYPE_STRING = "string";
+    private static final String TYPE_DRAWABLE = "drawable";
+
     public static final boolean DEBUG_JAR = false;
     public static final boolean DEBUG_BACKUP = false;
     public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
@@ -2021,6 +2029,24 @@
                 pkg.setManageSpaceActivityName(manageSpaceActivityName);
             }
 
+            if (Flags.changeLauncherBadging()) {
+                ParseResult<int[]> result = drawableResIdArray(input, sa, res,
+                        R.styleable.AndroidManifestApplication_alternateLauncherIcons,
+                        MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH);
+                if (result.isError()) {
+                    return input.error(result);
+                }
+                pkg.setAlternateLauncherIconResIds(result.getResult());
+
+                result = stringResIdArray(input, sa, res,
+                        R.styleable.AndroidManifestApplication_alternateLauncherLabels,
+                        MAXIMUM_LAUNCHER_ALTERNATE_IDS_LENGTH);
+                if (result.isError()) {
+                    return input.error(result);
+                }
+                pkg.setAlternateLauncherLabelResIds(result.getResult());
+            }
+
             if (pkg.isBackupAllowed()) {
                 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
                 // and restoreAnyVersion are only relevant if backup is possible for the
@@ -3395,6 +3421,95 @@
         return sa.getResourceId(attribute, 0);
     }
 
+    /**
+     * Parse the drawable resource id array in the typed array {@code resourceId}
+     * if available. If {@code maxSize} is not zero, only parse and preserve at most
+     * {@code maxSize} ids.
+     */
+    private static ParseResult<int[]> drawableResIdArray(ParseInput input, @NonNull TypedArray sa,
+            @NonNull Resources res, int resourceId, int maxSize) {
+        return resIdArray(input, sa, res, resourceId, TYPE_DRAWABLE, maxSize);
+    }
+
+    /**
+     * Parse the string resource id array in the typed array {@code resourceId}
+     * if available. If {@code maxSize} is not zero, only parse and preserve at most
+     * {@code maxSize} ids.
+     */
+    private static ParseResult<int[]> stringResIdArray(ParseInput input, @NonNull TypedArray sa,
+            @NonNull Resources res, int resourceId, int maxSize) {
+        return resIdArray(input, sa, res, resourceId, TYPE_STRING, maxSize);
+    }
+
+    /**
+     * Parse the resource id array in the typed array {@code resourceId}
+     * if available. If {@code maxSize} is larger than zero, only parse and preserve
+     * at most {@code maxSize} ids that type is matched to the {@code expectedTypeName}.
+     * Because the TypedArray allows mixed types in an array, if {@code expectedTypeName}
+     * is null, it means don't check the type.
+     */
+    private static ParseResult<int[]> resIdArray(ParseInput input, @NonNull TypedArray sa,
+            @NonNull Resources res, int resourceId, @Nullable String expectedTypeName,
+            int maxSize) {
+        if (!sa.hasValue(resourceId)) {
+            return input.success(null);
+        }
+
+        final int typeArrayResId = sa.getResourceId(resourceId, /* defValue= */ 0);
+        if (typeArrayResId == 0) {
+            return input.success(null);
+        }
+
+        // Parse the typedArray
+        try (TypedArray typedArray = res.obtainTypedArray(typeArrayResId)) {
+            final String typedArrayName = res.getResourceName(typeArrayResId);
+            final int length = typedArray.length();
+            if (maxSize > 0 && length > maxSize) {
+                return input.error(TextUtils.formatSimple(
+                        "The length of the typedArray (%s) is larger than %d.",
+                        typedArrayName, maxSize));
+            }
+            Set<Integer> resourceIdSet = new ArraySet<>();
+            for (int i = 0; i < length; i++) {
+                final int id = typedArray.getResourceId(i, /* defValue= */ 0);
+                // Add the id when the conditions are all matched:
+                // 1. The resource Id is not 0
+                // 2. The type is the expected type
+                // 3. The id is not duplicated
+                if (id == 0) {
+                    return input.error(TextUtils.formatSimple(
+                            "There is an item that is not a resource id in the typedArray (%s).",
+                            typedArrayName));
+                }
+
+                try {
+                    if (resourceIdSet.contains(id)) {
+                        return input.error(TextUtils.formatSimple(
+                                "There is a duplicated resource (%s) in the typedArray (%s).",
+                                res.getResourceName(id), typedArrayName));
+                    }
+                    final String typeName = res.getResourceTypeName(id);
+                    if (expectedTypeName != null
+                            && !TextUtils.equals(typeName, expectedTypeName)) {
+                        return input.error(TextUtils.formatSimple(
+                                "There is a resource (%s) in the typedArray (%s) that is not a"
+                                        + " %s type.", res.getResourceName(id), typedArrayName,
+                                expectedTypeName));
+                    }
+                } catch (Resources.NotFoundException e) {
+                    return input.error(TextUtils.formatSimple(
+                            "There is a resource in the typedArray (%s) that is not found in"
+                                    + " the app resources.", typedArrayName));
+                }
+                resourceIdSet.add(id);
+            }
+            if (resourceIdSet.isEmpty()) {
+                return input.success(null);
+            }
+            return input.success(resourceIdSet.stream().mapToInt(i -> i).toArray());
+        }
+    }
+
     private static String string(@StyleableRes int attribute, TypedArray sa) {
         return sa.getString(attribute);
     }
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index a1c987f..eb682df 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -676,15 +676,30 @@
         return internMap.get(string);
     }
 
+    protected boolean validateGroups(ILogger logger, String[] groups) {
+        for (int i = 0; i < groups.length; i++) {
+            String group = groups[i];
+            IProtoLogGroup g = mLogGroups.get(group);
+            if (g == null) {
+                logger.log("No IProtoLogGroup named " + group);
+                return false;
+            }
+        }
+        return true;
+    }
+
     private int setTextLogging(boolean value, ILogger logger, String... groups) {
+        if (!validateGroups(logger, groups)) {
+            return -1;
+        }
+
         for (int i = 0; i < groups.length; i++) {
             String group = groups[i];
             IProtoLogGroup g = mLogGroups.get(group);
             if (g != null) {
                 g.setLogToLogcat(value);
             } else {
-                logger.log("No IProtoLogGroup named " + group);
-                return -1;
+                throw new RuntimeException("No IProtoLogGroup named " + group);
             }
         }
 
diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
index 70d148a..967a5ed 100644
--- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java
@@ -113,6 +113,10 @@
      */
     @Override
     public int startLoggingToLogcat(String[] groups, @NonNull ILogger logger) {
+        if (!validateGroups(logger, groups)) {
+            return -1;
+        }
+
         mViewerConfigReader.loadViewerConfig(groups, logger);
         return super.startLoggingToLogcat(groups, logger);
     }
@@ -125,8 +129,19 @@
      */
     @Override
     public int stopLoggingToLogcat(String[] groups, @NonNull ILogger logger) {
+        if (!validateGroups(logger, groups)) {
+            return -1;
+        }
+
+        var status = super.stopLoggingToLogcat(groups, logger);
+
+        if (status != 0) {
+            throw new RuntimeException("Failed to stop logging to logcat");
+        }
+
+        // If we successfully disabled logging, unload the viewer config.
         mViewerConfigReader.unloadViewerConfig(groups, logger);
-        return super.stopLoggingToLogcat(groups, logger);
+        return status;
     }
 
     @Deprecated
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 3303d87..8df3f2a 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -88,15 +88,19 @@
     /** @hide */
     public static class CompatIdsForTest {
         // Enabled by default
+        /** Used for testing */
         @ChangeId
         public static final long TEST_COMPAT_ID_1 = 368131859L;
 
+        /** Used for testing */
         @Disabled
         @ChangeId public static final long TEST_COMPAT_ID_2 = 368131701L;
 
+        /** Used for testing */
         @EnabledAfter(targetSdkVersion = S)
         @ChangeId public static final long TEST_COMPAT_ID_3 = 368131659L;
 
+        /** Used for testing */
         @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE)
         @ChangeId public static final long TEST_COMPAT_ID_4 = 368132057L;
     }
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index f2b36c3..7a21275 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -59,6 +59,8 @@
 public final class NotificationProgressBar extends ProgressBar {
     private static final String TAG = "NotificationProgressBar";
 
+    private NotificationProgressDrawable mNotificationProgressDrawable;
+
     private NotificationProgressModel mProgressModel;
 
     @Nullable
@@ -94,6 +96,12 @@
                 defStyleAttr,
                 defStyleRes);
 
+        try {
+            mNotificationProgressDrawable = getNotificationProgressDrawable();
+        } catch (IllegalStateException ex) {
+            Log.e(TAG, "Can't get NotificationProgressDrawable", ex);
+        }
+
         // Supports setting the tracker in xml, but ProgressStyle notifications set/override it
         // via {@code setProgressTrackerIcon}.
         final Drawable tracker = a.getDrawable(R.styleable.NotificationProgressBar_tracker);
@@ -131,11 +139,8 @@
                     progressMax,
                     mProgressModel.isStyledByProgress());
 
-            try {
-                final NotificationProgressDrawable drawable = getNotificationProgressDrawable();
-                drawable.setParts(mProgressDrawableParts);
-            } catch (IllegalStateException ex) {
-                Log.e(TAG, "Can't set parts because can't get NotificationProgressDrawable", ex);
+            if (mNotificationProgressDrawable != null) {
+                mNotificationProgressDrawable.setParts(mProgressDrawableParts);
             }
 
             setMax(progressMax);
@@ -195,10 +200,6 @@
     }
 
     private void setTracker(@Nullable Drawable tracker) {
-        if (isIndeterminate() && tracker != null) {
-            return;
-        }
-
         final boolean needUpdate = mTracker != null && tracker != mTracker;
         if (needUpdate) {
             mTracker.setCallback(null);
@@ -222,6 +223,9 @@
         }
 
         mTracker = tracker;
+        if (mNotificationProgressDrawable != null) {
+            mNotificationProgressDrawable.setHasTrackerIcon(mTracker != null);
+        }
 
         configureTrackerBounds();
 
@@ -275,16 +279,6 @@
     }
 
     @Override
-    @RemotableViewMethod
-    public synchronized void setIndeterminate(boolean indeterminate) {
-        super.setIndeterminate(indeterminate);
-
-        if (isIndeterminate()) {
-            setTracker(null);
-        }
-    }
-
-    @Override
     protected boolean verifyDrawable(@NonNull Drawable who) {
         return who == mTracker || super.verifyDrawable(who);
     }
@@ -421,6 +415,8 @@
     @Override
     protected synchronized void onDraw(Canvas canvas) {
         super.onDraw(canvas);
+
+        if (isIndeterminate()) return;
         drawTracker(canvas);
     }
 
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
index fb6937c..e95225e 100644
--- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -23,7 +23,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.DashPathEffect;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -62,21 +61,15 @@
     private boolean mMutated;
 
     private final ArrayList<Part> mParts = new ArrayList<>();
+    private boolean mHasTrackerIcon;
 
     private final RectF mSegRectF = new RectF();
     private final Rect mPointRect = new Rect();
     private final RectF mPointRectF = new RectF();
 
-    private final Paint mStrokePaint = new Paint();
-    private final Paint mDashedStrokePaint = new Paint();
     private final Paint mFillPaint = new Paint();
 
     {
-        mStrokePaint.setStyle(Paint.Style.STROKE);
-        mStrokePaint.setStrokeCap(Paint.Cap.ROUND);
-
-        mDashedStrokePaint.setStyle(Paint.Style.STROKE);
-
         mFillPaint.setStyle(Paint.Style.FILL);
     }
 
@@ -87,49 +80,15 @@
     }
 
     /**
-     * <p>Set the stroke width and default color for the drawable.</p>
-     * <p>Note: changing this property will affect all instances of a drawable loaded from a
-     * resource. It is recommended to invoke
-     * {@link #mutate()} before changing this property.</p>
-     *
-     * @param width The width in pixels of the stroke
-     * @param color The color of the stroke
-     * @see #mutate()
-     * @see #setStroke(int, int, float, float)
-     */
-    public void setStroke(int width, @ColorInt int color) {
-        setStroke(width, color, 0, 0);
-    }
-
-    /**
-     * <p>Set the stroke width and default color for the drawable. This method can also be used
-     * to dash the stroke for the dashed segments.</p>
-     * <p>Note: changing this property will affect all instances of a drawable loaded from a
-     * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
-     *
-     * @param width     The width in pixels of the stroke
-     * @param color     The color of the stroke
-     * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
-     * @param dashGap   The gap in pixels between dashes
-     * @see #mutate()
-     * @see #setStroke(int, int)
-     */
-    public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
-        mState.setStroke(width, color, dashWidth, dashGap);
-        setStrokeInternal(width, dashWidth, dashGap);
-    }
-
-    /**
-     * <p>Set the stroke default color for the drawable.</p>
+     * <p>Set the segment default color for the drawable.</p>
      * <p>Note: changing this property will affect all instances of a drawable loaded from a
      * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p>
      *
      * @param color The color of the stroke
      * @see #mutate()
-     * @see #setStroke(int, int, float, float)
      */
-    public void setStrokeDefaultColor(@ColorInt int color) {
-        mState.setStrokeColor(color);
+    public void setSegmentDefaultColor(@ColorInt int color) {
+        mState.setSegmentColor(color);
     }
 
     /**
@@ -144,15 +103,12 @@
         mState.setPointRectColor(color);
     }
 
-    private void setStrokeInternal(int width, float dashWidth, float dashGap) {
-        mStrokePaint.setStrokeWidth(width);
-
-        mDashedStrokePaint.setStrokeWidth(width);
-        DashPathEffect e = null;
-        if (dashWidth > 0) {
-            e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0);
-        }
-        mDashedStrokePaint.setPathEffect(e);
+    /**
+     * Set the segments and points that constitute the drawable.
+     */
+    public void setParts(List<Part> parts) {
+        mParts.clear();
+        mParts.addAll(parts);
 
         invalidateSelf();
     }
@@ -160,16 +116,18 @@
     /**
      * Set the segments and points that constitute the drawable.
      */
-    public void setParts(List<Part> parts) {
-        mParts.clear();
-        mParts.addAll(parts);
+    public void setParts(@NonNull Part... parts) {
+        setParts(Arrays.asList(parts));
     }
 
     /**
-     * Set the segments and points that constitute the drawable.
+     * Set whether a tracker is drawn on top of this NotificationProgressDrawable.
      */
-    public void setParts(@NonNull Part... parts) {
-        setParts(Arrays.asList(parts));
+    public void setHasTrackerIcon(boolean hasTrackerIcon) {
+        if (mHasTrackerIcon != hasTrackerIcon) {
+            mHasTrackerIcon = hasTrackerIcon;
+            invalidateSelf();
+        }
     }
 
     @Override
@@ -181,6 +139,7 @@
         float x = (float) getBounds().left;
         final float centerY = (float) getBounds().centerY();
         final float totalWidth = (float) getBounds().width();
+        float segPointGap = mState.mSegPointGap;
 
         final int numParts = mParts.size();
         for (int iPart = 0; iPart < numParts; iPart++) {
@@ -188,15 +147,19 @@
             final Part prevPart = iPart == 0 ? null : mParts.get(iPart - 1);
             final Part nextPart = iPart + 1 == numParts ? null : mParts.get(iPart + 1);
             if (part instanceof Segment segment) {
+                // Update the segment-point gap to 2X upon seeing the first faded segment.
+                // (Assuming that all segments before are solid, and all segments after are faded.)
+                if (segment.mFaded) {
+                    segPointGap = mState.mSegPointGap * 2;
+                }
                 final float segWidth = segment.mFraction * totalWidth;
                 // Advance the start position to account for a point immediately prior.
-                final float startOffset = getSegStartOffset(prevPart, pointRadius,
-                        mState.mSegPointGap, x);
+                final float startOffset = getSegStartOffset(prevPart, pointRadius, segPointGap, x);
                 final float start = x + startOffset;
                 // Retract the end position to account for the padding and a point immediately
                 // after.
-                final float endOffset = getSegEndOffset(nextPart, pointRadius, mState.mSegPointGap,
-                        mState.mSegSegGap, x + segWidth, totalWidth);
+                final float endOffset = getSegEndOffset(segment, nextPart, pointRadius, segPointGap,
+                        mState.mSegSegGap, x + segWidth, totalWidth, mHasTrackerIcon);
                 final float end = x + segWidth - endOffset;
 
                 // Advance the current position to account for the segment's fraction of the total
@@ -206,35 +169,15 @@
                 // No space left to draw the segment
                 if (start > end) continue;
 
-                if (segment.mDashed) {
-                    // No caps when the segment is dashed.
+                final float radiusY = segment.mFaded ? mState.mFadedSegmentHeight / 2F
+                        : mState.mSegmentHeight / 2F;
+                final float cornerRadius = mState.mSegmentCornerRadius;
 
-                    mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
-                            : mState.mFadedStrokeColor);
-                    canvas.drawLine(start, centerY, end, centerY, mDashedStrokePaint);
-                } else if (end - start < mState.mStrokeWidth) {
-                    // Not enough segment length to draw the caps
+                mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
+                        : (segment.mFaded ? mState.mFadedSegmentColor : mState.mSegmentColor));
 
-                    final float rad = (end - start) / 2F;
-                    final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
-
-                    mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
-                            : mState.mStrokeColor);
-
-                    mSegRectF.set(start, centerY - capWidth, end, centerY + capWidth);
-                    canvas.drawRoundRect(mSegRectF, rad, rad, mFillPaint);
-                } else {
-                    // Leave space for the rounded line cap which extends beyond start/end.
-                    final float capWidth = mStrokePaint.getStrokeWidth() / 2F;
-
-                    // Transparent is not allowed (and also is the default in the data), so use that
-                    // as a sentinel to be replaced by default
-                    mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor
-                            : mState.mStrokeColor);
-
-                    canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY,
-                            mStrokePaint);
-                }
+                mSegRectF.set(start, centerY - radiusY, end, centerY + radiusY);
+                canvas.drawRoundRect(mSegRectF, cornerRadius, cornerRadius, mFillPaint);
             } else if (part instanceof Point point) {
                 final float pointWidth = 2 * pointRadius;
                 float start = x - pointRadius;
@@ -275,10 +218,17 @@
         return pointOffset + pointRadius + segPointGap;
     }
 
-    private static float getSegEndOffset(Part nextPart, float pointRadius, float segPointGap,
-            float segSegGap, float endX, float totalWidth) {
+    private static float getSegEndOffset(Segment seg, Part nextPart, float pointRadius,
+            float segPointGap,
+            float segSegGap, float endX, float totalWidth, boolean hasTrackerIcon) {
         if (nextPart == null) return 0F;
-        if (!(nextPart instanceof Point)) return segSegGap;
+        if (nextPart instanceof Segment nextSeg) {
+            if (!seg.mFaded && nextSeg.mFaded) {
+                // @see Segment#mFaded
+                return hasTrackerIcon ? 0F : segSegGap * 4F;
+            }
+            return segSegGap;
+        }
 
         final float pointWidth = 2 * pointRadius;
         final float pointOffset = (endX + pointRadius > totalWidth && totalWidth > pointWidth)
@@ -439,21 +389,17 @@
         // Extract the theme attributes, if any.
         state.mThemeAttrsSegments = a.extractThemeAttrs();
 
-        final int width = a.getDimensionPixelSize(
-                R.styleable.NotificationProgressDrawableSegments_width, state.mStrokeWidth);
-        final float dashWidth = a.getDimension(
-                R.styleable.NotificationProgressDrawableSegments_dashWidth, state.mStrokeDashWidth);
-
+        state.mSegmentHeight = a.getDimension(
+                R.styleable.NotificationProgressDrawableSegments_height, state.mSegmentHeight);
+        state.mFadedSegmentHeight = a.getDimension(
+                R.styleable.NotificationProgressDrawableSegments_fadedHeight,
+                state.mFadedSegmentHeight);
+        state.mSegmentCornerRadius = a.getDimension(
+                R.styleable.NotificationProgressDrawableSegments_cornerRadius,
+                state.mSegmentCornerRadius);
         final int color = a.getColor(R.styleable.NotificationProgressDrawableSegments_color,
-                state.mStrokeColor);
-
-        if (dashWidth != 0.0f) {
-            final float dashGap = a.getDimension(
-                    R.styleable.NotificationProgressDrawableSegments_dashGap, state.mStrokeDashGap);
-            setStroke(width, color, dashWidth, dashGap);
-        } else {
-            setStroke(width, color);
-        }
+                state.mSegmentColor);
+        setSegmentDefaultColor(color);
     }
 
     private void updatePointsFromTypedArray(TypedArray a) {
@@ -532,11 +478,24 @@
     /**
      * A segment is a part of the progress bar with non-zero length. For example, it can
      * represent a portion in a navigation journey with certain traffic condition.
+     *
      */
     public static final class Segment implements Part {
         private final float mFraction;
         @ColorInt private final int mColor;
-        private final boolean mDashed;
+        /** Whether the segment is faded or not.
+         * <p>
+         *     <pre>
+         *     When mFaded is set to true, a combination of the following is done to the segment:
+         *       1. The drawing color is mColor with opacity updated to 15%.
+         *       2. The segment-point gap is 2X the segment-point gap for non-faded segments.
+         *       3. The gap between faded and non-faded segments is:
+         *          4X the segment-segment gap, when there is no tracker icon
+         *          0, when there is tracker icon
+         *     </pre>
+         * </p>
+         */
+        private final boolean mFaded;
 
         public Segment(float fraction) {
             this(fraction, Color.TRANSPARENT);
@@ -546,10 +505,10 @@
             this(fraction, color, false);
         }
 
-        public Segment(float fraction, @ColorInt int color, boolean dashed) {
+        public Segment(float fraction, @ColorInt int color, boolean faded) {
             mFraction = fraction;
             mColor = color;
-            mDashed = dashed;
+            mFaded = faded;
         }
 
         public float getFraction() {
@@ -560,14 +519,14 @@
             return this.mColor;
         }
 
-        public boolean getDashed() {
-            return this.mDashed;
+        public boolean getFaded() {
+            return this.mFaded;
         }
 
         @Override
         public String toString() {
-            return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", dashed="
-                    + this.mDashed + ')';
+            return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", faded="
+                    + this.mFaded + ')';
         }
 
         // Needed for unit tests
@@ -580,12 +539,12 @@
             Segment that = (Segment) other;
             if (Float.compare(this.mFraction, that.mFraction) != 0) return false;
             if (this.mColor != that.mColor) return false;
-            return this.mDashed == that.mDashed;
+            return this.mFaded == that.mFaded;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(mFraction, mColor, mDashed);
+            return Objects.hash(mFraction, mColor, mFaded);
         }
     }
 
@@ -675,11 +634,11 @@
         int mChangingConfigurations;
         float mSegSegGap = 0.0f;
         float mSegPointGap = 0.0f;
-        int mStrokeWidth = 0;
-        int mStrokeColor;
-        int mFadedStrokeColor;
-        float mStrokeDashWidth = 0.0f;
-        float mStrokeDashGap = 0.0f;
+        float mSegmentHeight;
+        float mFadedSegmentHeight;
+        float mSegmentCornerRadius;
+        int mSegmentColor;
+        int mFadedSegmentColor;
         float mPointRadius;
         float mPointRectInset;
         float mPointRectCornerRadius;
@@ -699,11 +658,11 @@
             mChangingConfigurations = orig.mChangingConfigurations;
             mSegSegGap = orig.mSegSegGap;
             mSegPointGap = orig.mSegPointGap;
-            mStrokeWidth = orig.mStrokeWidth;
-            mStrokeColor = orig.mStrokeColor;
-            mFadedStrokeColor = orig.mFadedStrokeColor;
-            mStrokeDashWidth = orig.mStrokeDashWidth;
-            mStrokeDashGap = orig.mStrokeDashGap;
+            mSegmentHeight = orig.mSegmentHeight;
+            mFadedSegmentHeight = orig.mFadedSegmentHeight;
+            mSegmentCornerRadius = orig.mSegmentCornerRadius;
+            mSegmentColor = orig.mSegmentColor;
+            mFadedSegmentColor = orig.mFadedSegmentColor;
             mPointRadius = orig.mPointRadius;
             mPointRectInset = orig.mPointRectInset;
             mPointRectCornerRadius = orig.mPointRectCornerRadius;
@@ -721,17 +680,17 @@
         }
 
         private void applyDensityScaling(int sourceDensity, int targetDensity) {
-            if (mStrokeWidth > 0) {
-                mStrokeWidth = scaleFromDensity(
-                        mStrokeWidth, sourceDensity, targetDensity, true);
+            if (mSegmentHeight > 0) {
+                mSegmentHeight = scaleFromDensity(
+                        mSegmentHeight, sourceDensity, targetDensity);
             }
-            if (mStrokeDashWidth > 0) {
-                mStrokeDashWidth = scaleFromDensity(
-                        mStrokeDashWidth, sourceDensity, targetDensity);
+            if (mFadedSegmentHeight > 0) {
+                mFadedSegmentHeight = scaleFromDensity(
+                        mFadedSegmentHeight, sourceDensity, targetDensity);
             }
-            if (mStrokeDashGap > 0) {
-                mStrokeDashGap = scaleFromDensity(
-                        mStrokeDashGap, sourceDensity, targetDensity);
+            if (mSegmentCornerRadius > 0) {
+                mSegmentCornerRadius = scaleFromDensity(
+                        mSegmentCornerRadius, sourceDensity, targetDensity);
             }
             if (mPointRadius > 0) {
                 mPointRadius = scaleFromDensity(
@@ -788,17 +747,9 @@
             }
         }
 
-        public void setStroke(int width, int color, float dashWidth, float dashGap) {
-            mStrokeWidth = width;
-            mStrokeDashWidth = dashWidth;
-            mStrokeDashGap = dashGap;
-
-            setStrokeColor(color);
-        }
-
-        public void setStrokeColor(int color) {
-            mStrokeColor = color;
-            mFadedStrokeColor = getFadedColor(color);
+        public void setSegmentColor(int color) {
+            mSegmentColor = color;
+            mFadedSegmentColor = getFadedColor(color);
         }
 
         public void setPointRectColor(int color) {
@@ -808,11 +759,14 @@
     }
 
     /**
-     * Get a color with an opacity that's 50% of the input color.
+     * Get a color with an opacity that's 25% of the input color.
      */
     @ColorInt
     static int getFadedColor(@ColorInt int color) {
-        return Color.argb(Color.alpha(color) / 2, Color.red(color), Color.green(color),
+        return Color.argb(
+                (int) (Color.alpha(color) * 0.25f + 0.5f),
+                Color.red(color),
+                Color.green(color),
                 Color.blue(color));
     }
 
@@ -836,15 +790,6 @@
     }
 
     private void updateLocalState() {
-        final State state = mState;
-
-        mStrokePaint.setStrokeWidth(state.mStrokeWidth);
-        mDashedStrokePaint.setStrokeWidth(state.mStrokeWidth);
-
-        if (state.mStrokeDashWidth != 0.0f) {
-            final DashPathEffect e = new DashPathEffect(
-                    new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0);
-            mDashedStrokePaint.setPathEffect(e);
-        }
+        // NO-OP
     }
 }
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index 5350059..d05f5e3 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -91,6 +91,28 @@
 public interface AndroidPackage {
 
     /**
+     * An array containing the drawable resources that used for the launcher
+     * activity icons.
+     *
+     * @see R.attr#alternateLauncherIcons
+     * @hide
+     */
+    @Immutable.Ignore
+    @Nullable
+    int[] getAlternateLauncherIconResIds();
+
+    /**
+     * An array containing the string resources that used for the launcher
+     * activity labels.
+     *
+     * @see R.attr#alternateLauncherLabels
+     * @hide
+     */
+    @Immutable.Ignore
+    @Nullable
+    int[] getAlternateLauncherLabelResIds();
+
+    /**
      * @see ApplicationInfo#className
      * @see R.styleable#AndroidManifestApplication_name
      */
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 2541258..a21bf9a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -77,6 +77,7 @@
         "android_os_SystemClock.cpp",
         "android_os_SystemProperties.cpp",
         "android_text_AndroidCharacter.cpp",
+        "android_text_Hyphenator.cpp",
         "android_util_AssetManager.cpp",
         "android_util_EventLog.cpp",
         "android_util_Log.cpp",
@@ -166,7 +167,6 @@
                 "android_view_SurfaceSession.cpp",
                 "android_view_TextureView.cpp",
                 "android_view_TunnelModeEnabledListener.cpp",
-                "android_text_Hyphenator.cpp",
                 "android_os_Debug.cpp",
                 "android_os_GraphicsEnvironment.cpp",
                 "android_os_HidlMemory.cpp",
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index bb4084e..f64dec8 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -106,7 +106,7 @@
                                                                         jlong nativeObject) {
     gui::OverlayProperties* overlayProperties =
             reinterpret_cast<gui::OverlayProperties*>(nativeObject);
-    if (overlayProperties->lutProperties.has_value()) {
+    if (!overlayProperties || !overlayProperties->lutProperties) {
         return NULL;
     }
     auto& lutProperties = overlayProperties->lutProperties.value();
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8eaa7aa..3d9a19e 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -109,6 +109,7 @@
     // Valid only if an AudioDevicePort
     jfieldID    mType;
     jfieldID    mAddress;
+    jfieldID mSpeakerLayoutChannelMask;
     // other fields unused by JNI
 } gAudioPortFields;
 
@@ -1084,6 +1085,8 @@
     strncpy(nAudioPortConfig->ext.device.address,
             nDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN - 1);
     env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
+    nAudioPortConfig->ext.device.speaker_layout_channel_mask = outChannelMaskToNative(
+            env->GetIntField(jAudioDevicePort, gAudioPortFields.mSpeakerLayoutChannelMask));
     env->DeleteLocalRef(jDeviceAddress);
     env->DeleteLocalRef(jAudioDevicePort);
     return jStatus;
@@ -1541,10 +1544,12 @@
                                                            .encapsulation_metadata_types));
         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
         ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(nAudioPort->ext.device.address));
+        int speakerLayoutChannelMask = outChannelMaskFromNative(
+                nAudioPort->active_config.ext.device.speaker_layout_channel_mask);
         jAudioPort->reset(env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
                                          jHandle.get(), jDeviceName.get(), jAudioProfiles.get(),
                                          jGains.get(), nAudioPort->ext.device.type, jAddress.get(),
-                                         jEncapsulationModes.get(),
+                                         speakerLayoutChannelMask, jEncapsulationModes.get(),
                                          jEncapsulationMetadataTypes.get(),
                                          jAudioDescriptors.get()));
     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
@@ -3705,14 +3710,15 @@
     gAudioDevicePortCstor =
             GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
                              "(Landroid/media/AudioHandle;Ljava/lang/String;Ljava/util/List;"
-                             "[Landroid/media/AudioGain;ILjava/lang/String;[I[I"
+                             "[Landroid/media/AudioGain;ILjava/lang/String;I[I[I"
                              "Ljava/util/List;)V");
 
     // When access AudioPort as AudioDevicePort
     gAudioPortFields.mType = GetFieldIDOrDie(env, audioDevicePortClass, "mType", "I");
     gAudioPortFields.mAddress = GetFieldIDOrDie(env, audioDevicePortClass, "mAddress",
             "Ljava/lang/String;");
-
+    gAudioPortFields.mSpeakerLayoutChannelMask =
+            GetFieldIDOrDie(env, audioDevicePortClass, "mSpeakerLayoutChannelMask", "I");
     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
     gAudioMixPortCstor =
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 933781c..e45cbaf 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -18,10 +18,17 @@
 #include <cutils/trace.h>
 #include <fcntl.h>
 #include <minikin/Hyphenator.h>
+#ifdef __ANDROID__
 #include <sys/mman.h>
+#else
+#include <android-base/mapped_file.h>
+#include <android-base/properties.h>
+#endif
 #include <sys/stat.h>
 #include <sys/types.h>
+#ifdef __ANDROID__
 #include <tracing_perfetto.h>
+#endif
 #include <unicode/uloc.h>
 #include <unistd.h>
 
@@ -30,7 +37,12 @@
 namespace android {
 
 static std::string buildFileName(const std::string& locale) {
+#ifdef __ANDROID__
     constexpr char SYSTEM_HYPHENATOR_PREFIX[] = "/system/usr/hyphen-data/hyph-";
+#else
+    std::string hyphenPath = base::GetProperty("ro.hyphen.data.dir", "/system/usr/hyphen-data");
+    std::string SYSTEM_HYPHENATOR_PREFIX = hyphenPath + "/hyph-";
+#endif
     constexpr char SYSTEM_HYPHENATOR_SUFFIX[] = ".hyb";
     std::string lowerLocale;
     lowerLocale.reserve(locale.size());
@@ -51,11 +63,22 @@
         return std::make_pair(nullptr, 0);
     }
 
+#ifdef __ANDROID__
     void* ptr = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0 /* offset */);
     close(fd);
     if (ptr == MAP_FAILED) {
         return std::make_pair(nullptr, 0);
     }
+#else
+    std::unique_ptr<base::MappedFile> patternFile =
+            base::MappedFile::FromFd(fd, 0, st.st_size, PROT_READ);
+    close(fd);
+    if (patternFile == nullptr) {
+        return std::make_pair(nullptr, 0);
+    }
+    auto* mappedPtr = new base::MappedFile(std::move(*patternFile));
+    char* ptr = mappedPtr->data();
+#endif
     return std::make_pair(reinterpret_cast<const uint8_t*>(ptr), st.st_size);
 }
 
@@ -210,9 +233,13 @@
     addHyphenatorAlias("und-Taml", "ta");  // Tamil
     addHyphenatorAlias("und-Telu", "te");  // Telugu
 
+#ifdef __ANDROID__
     tracing_perfetto::traceBegin(ATRACE_TAG_VIEW, "CacheUnicodeExtensionSubtagsKeyMap");
+#endif
     cacheUnicodeExtensionSubtagsKeyMap();
+#ifdef __ANDROID__
     tracing_perfetto::traceEnd(ATRACE_TAG_VIEW); // CacheUnicodeExtensionSubtagsKeyMap
+#endif
 }
 
 static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 49191ee..7ef7829 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
 
 #include <algorithm>
 #include <array>
+#include <cctype>
 #include <cstring>
 #include <limits>
 #include <memory>
@@ -1008,6 +1009,8 @@
                 }
             }
             if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
+                std::replace_if(buffer+start, buffer+end,
+                                [](unsigned char c){ return !std::isprint(c); }, '?');
                 jstring str = env->NewStringUTF(buffer+start);
                 env->SetObjectArrayElement(outStrings, di, str);
             }
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index f007cc5..a09c405 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -67,6 +67,7 @@
         jfieldID preferredFrameTimelineIndex;
         jfieldID frameTimelinesLength;
         jfieldID frameTimelines;
+        jfieldID numberQueuedBuffers;
     } vsyncEventDataClassInfo;
 
 } gDisplayEventReceiverClassInfo;
@@ -165,7 +166,8 @@
     return env->NewObject(gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init,
                           frameTimelineObjs.get(), vsyncEventData.preferredFrameTimelineIndex,
-                          vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval);
+                          vsyncEventData.frameTimelinesLength, vsyncEventData.frameInterval,
+                          vsyncEventData.numberQueuedBuffers);
 }
 
 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -188,6 +190,9 @@
         env->SetLongField(vsyncEventDataObj.get(),
                           gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
                           vsyncEventData.frameInterval);
+        env->SetIntField(vsyncEventDataObj.get(),
+                         gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.numberQueuedBuffers,
+                         vsyncEventData.numberQueuedBuffers);
 
         ScopedLocalRef<jobjectArray>
                 frameTimelinesObj(env,
@@ -441,7 +446,7 @@
             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
                              "<init>",
                              "([Landroid/view/"
-                             "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJ)V");
+                             "DisplayEventReceiver$VsyncEventData$FrameTimeline;IIJI)V");
 
     gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
@@ -456,6 +461,9 @@
             GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
                             "frameTimelines",
                             "[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
+    gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.numberQueuedBuffers =
+            GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+                            "numberQueuedBuffers", "I");
 
     return res;
 }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d3bf36e..593b982 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -758,54 +758,64 @@
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
 
-    ScopedIntArrayRW joffsets(env, joffsetArray);
-    if (joffsets.get() == nullptr) {
-        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
-        return;
-    }
-    ScopedIntArrayRW jdimensions(env, jdimensionArray);
-    if (jdimensions.get() == nullptr) {
-        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
-        return;
-    }
-    ScopedIntArrayRW jsizes(env, jsizeArray);
-    if (jsizes.get() == nullptr) {
-        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
-        return;
-    }
-    ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
-    if (jsamplingKeys.get() == nullptr) {
-        jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
-        return;
-    }
+    std::vector<int32_t> offsets;
+    std::vector<int32_t> dimensions;
+    std::vector<int32_t> sizes;
+    std::vector<int32_t> samplingKeys;
+    int32_t fd = -1;
 
-    jsize numLuts = env->GetArrayLength(jdimensionArray);
-    std::vector<int32_t> offsets(joffsets.get(), joffsets.get() + numLuts);
-    std::vector<int32_t> dimensions(jdimensions.get(), jdimensions.get() + numLuts);
-    std::vector<int32_t> sizes(jsizes.get(), jsizes.get() + numLuts);
-    std::vector<int32_t> samplingKeys(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
+    if (jdimensionArray) {
+        jsize numLuts = env->GetArrayLength(jdimensionArray);
+        ScopedIntArrayRW joffsets(env, joffsetArray);
+        if (joffsets.get() == nullptr) {
+            jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
+            return;
+        }
+        ScopedIntArrayRW jdimensions(env, jdimensionArray);
+        if (jdimensions.get() == nullptr) {
+            jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
+            return;
+        }
+        ScopedIntArrayRW jsizes(env, jsizeArray);
+        if (jsizes.get() == nullptr) {
+            jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
+            return;
+        }
+        ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
+        if (jsamplingKeys.get() == nullptr) {
+            jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
+            return;
+        }
 
-    ScopedFloatArrayRW jbuffers(env, jbufferArray);
-    if (jbuffers.get() == nullptr) {
-        jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
-        return;
-    }
+        if (numLuts > 0) {
+            offsets = std::vector<int32_t>(joffsets.get(), joffsets.get() + numLuts);
+            dimensions = std::vector<int32_t>(jdimensions.get(), jdimensions.get() + numLuts);
+            sizes = std::vector<int32_t>(jsizes.get(), jsizes.get() + numLuts);
+            samplingKeys = std::vector<int32_t>(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
 
-    // create the shared memory and copy jbuffers
-    size_t bufferSize = jbuffers.size() * sizeof(float);
-    int32_t fd = ashmem_create_region("lut_shread_mem", bufferSize);
-    if (fd < 0) {
-        jniThrowRuntimeException(env, "ashmem_create_region() failed");
-        return;
+            ScopedFloatArrayRW jbuffers(env, jbufferArray);
+            if (jbuffers.get() == nullptr) {
+                jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
+                return;
+            }
+
+            // create the shared memory and copy jbuffers
+            size_t bufferSize = jbuffers.size() * sizeof(float);
+            fd = ashmem_create_region("lut_shared_mem", bufferSize);
+            if (fd < 0) {
+                jniThrowRuntimeException(env, "ashmem_create_region() failed");
+                return;
+            }
+            void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+            if (ptr == MAP_FAILED) {
+                jniThrowRuntimeException(env, "Failed to map the shared memory");
+                return;
+            }
+            memcpy(ptr, jbuffers.get(), bufferSize);
+            // unmap
+            munmap(ptr, bufferSize);
+        }
     }
-    void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (ptr == MAP_FAILED) {
-        jniThrowRuntimeException(env, "Failed to map the shared memory");
-        return;
-    }
-    memcpy(ptr, jbuffers.get(), bufferSize);
-    // unmap
-    munmap(ptr, bufferSize);
 
     transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys);
 }
@@ -1332,8 +1342,9 @@
     }
 }
 
-static jobject convertDeviceProductInfoToJavaObject(
-        JNIEnv* env, const std::optional<DeviceProductInfo>& info) {
+static jobject convertDeviceProductInfoToJavaObject(JNIEnv* env,
+                                                    const std::optional<DeviceProductInfo>& info,
+                                                    bool isInternal) {
     using ModelYear = android::DeviceProductInfo::ModelYear;
     using ManufactureYear = android::DeviceProductInfo::ManufactureYear;
     using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear;
@@ -1368,7 +1379,8 @@
     // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
     using android::hardware::display::IDeviceProductInfoConstants;
     if (info->relativeAddress.size() != 4) {
-        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+        connectionToSinkType = isInternal ? IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN
+                                          : IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
     } else if (info->relativeAddress[0] == 0) {
         connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
     } else if (info->relativeAddress[1] == 0) {
@@ -1390,12 +1402,14 @@
 
     jobject object =
             env->NewObject(gStaticDisplayInfoClassInfo.clazz, gStaticDisplayInfoClassInfo.ctor);
-    env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal,
-                         info.connectionType == ui::DisplayConnectionType::Internal);
+
+    const bool isInternal = info.connectionType == ui::DisplayConnectionType::Internal;
+    env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal, isInternal);
     env->SetFloatField(object, gStaticDisplayInfoClassInfo.density, info.density);
     env->SetBooleanField(object, gStaticDisplayInfoClassInfo.secure, info.secure);
     env->SetObjectField(object, gStaticDisplayInfoClassInfo.deviceProductInfo,
-                        convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo));
+                        convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo,
+                                                             isInternal));
     env->SetIntField(object, gStaticDisplayInfoClassInfo.installOrientation,
                      static_cast<uint32_t>(info.installOrientation));
     return object;
@@ -2163,7 +2177,7 @@
 
 class JankDataListenerWrapper : public JankDataListener {
 public:
-    JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
+    JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) : mRemovedVsyncId(-1) {
         mOnJankDataListenerWeak = env->NewWeakGlobalRef(onJankDataListenerObject);
         env->GetJavaVM(&mVm);
     }
@@ -2174,6 +2188,12 @@
     }
 
     bool onJankDataAvailable(const std::vector<gui::JankData>& jankData) override {
+        // Don't invoke the listener if we've been force removed and got this
+        // out-of-order callback.
+        if (mRemovedVsyncId == 0) {
+            return false;
+        }
+
         JNIEnv* env = getEnv();
 
         jobject target = env->NewLocalRef(mOnJankDataListenerWeak);
@@ -2181,8 +2201,8 @@
             return false;
         }
 
-        jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(),
-                gJankDataClassInfo.clazz, nullptr);
+        jobjectArray jJankDataArray =
+                env->NewObjectArray(jankData.size(), gJankDataClassInfo.clazz, nullptr);
         for (size_t i = 0; i < jankData.size(); i++) {
             // The exposed constants in SurfaceControl are simplified, so we need to translate the
             // jank type we get from SF to what is exposed in Java.
@@ -2225,6 +2245,11 @@
         return true;
     }
 
+    void removeListener(int64_t afterVsyncId) {
+        mRemovedVsyncId = (afterVsyncId <= 0) ? 0 : afterVsyncId;
+        JankDataListener::removeListener(afterVsyncId);
+    }
+
 private:
 
     JNIEnv* getEnv() {
@@ -2235,6 +2260,7 @@
 
     JavaVM* mVm;
     jobject mOnJankDataListenerWeak;
+    int64_t mRemovedVsyncId;
 };
 
 static jlong nativeCreateJankDataListenerWrapper(JNIEnv* env, jclass clazz,
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp
index 6c72544..76ead2a 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.cpp
+++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp
@@ -22,7 +22,6 @@
 #include <android-base/hex.h>
 #include <android-base/unique_fd.h>
 #include <bionic/macros.h>
-#include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -204,7 +203,8 @@
     return true;
 }
 
-bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
+bool getLoadSegmentPhdrs(const char *filePath, const uint64_t offset,
+                         std::vector<Elf64_Phdr> &programHeaders) {
     // Open Elf file
     Elf64_Ehdr ehdr;
     std::ifstream inputStream(filePath, std::ifstream::in);
@@ -227,11 +227,6 @@
     uint64_t programHeaderOffset = ehdr.e_phoff;
     uint16_t programHeaderNum = ehdr.e_phnum;
 
-    IF_ALOGD() {
-        ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu",
-              filePath, programHeaderOffset, programHeaderNum);
-    }
-
     // if this is a zip file, also consider elf offset inside a file
     uint64_t phOffset;
     if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) {
@@ -240,7 +235,6 @@
     }
     inputStream.seekg(phOffset);
 
-    std::vector<Elf64_Phdr> programHeaders;
     for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) {
         Elf64_Phdr header;
         inputStream.read((char *)&header, sizeof(header));
@@ -254,6 +248,15 @@
         programHeaders.push_back(header);
     }
 
+    return true;
+}
+
+bool punchHolesInElf64(const char *filePath, const uint64_t offset) {
+    std::vector<Elf64_Phdr> programHeaders;
+    if (!getLoadSegmentPhdrs(filePath, offset, programHeaders)) {
+        ALOGE("Failed to read program headers from ELF file.");
+        return false;
+    }
     return punchHoles(filePath, offset, programHeaders);
 }
 
diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h
index 52445e2..4a95686c 100644
--- a/core/jni/com_android_internal_content_FileSystemUtils.h
+++ b/core/jni/com_android_internal_content_FileSystemUtils.h
@@ -15,8 +15,11 @@
  */
 #pragma once
 
+#include <elf.h>
 #include <sys/types.h>
 
+#include <vector>
+
 namespace android {
 
 /*
@@ -35,4 +38,11 @@
  */
 bool punchHolesInZip(const char* filePath, uint64_t offset, uint16_t extraFieldLen);
 
+/*
+ * This function reads program headers from ELF file. ELF can be specified with file path directly
+ * or it should be at offset inside Apk. Program headers passed to function is populated.
+ */
+bool getLoadSegmentPhdrs(const char* filePath, const uint64_t offset,
+                         std::vector<Elf64_Phdr>& programHeaders);
+
 } // namespace android
\ No newline at end of file
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 7fca117..1a03283 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -88,6 +88,7 @@
 extern int register_android_os_SystemClock(JNIEnv* env);
 extern int register_android_os_SystemProperties(JNIEnv* env);
 extern int register_android_text_AndroidCharacter(JNIEnv* env);
+extern int register_android_text_Hyphenator(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
@@ -133,6 +134,7 @@
         {"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
         {"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
         {"android.text.AndroidCharacter", REG_JNI(register_android_text_AndroidCharacter)},
+        {"android.text.Hyphenator", REG_JNI(register_android_text_Hyphenator)},
         {"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
         {"android.util.Log", REG_JNI(register_android_util_Log)},
         {"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3e0c120..0046405 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -914,13 +914,26 @@
                 android:featureFlag="android.provider.user_keys" />
 
     <!-- Allows an application to set default account for new contacts.
-        <p> This permission is only granted to system applications fulfilling the Contacts app role.
+        <p>This permission is only granted to system applications fulfilling the Contacts app role.
         <p>Protection level: internal|role
         @SystemApi
         @hide
     -->
     <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
-        android:protectionLevel="internal|role" />
+        android:protectionLevel="internal|role"
+        android:featureFlag="!android.provider.new_default_account_api_enabled"/>
+
+    <!-- Allows an application to set default account for new contacts.
+        <p>This permission is only granted to system applications fulfilling the Contacts app role
+        and the application with known signers.
+        <p>Protection level: internal|role|knownSigner
+        @SystemApi
+        @hide
+    -->
+    <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS"
+        android:protectionLevel="internal|role|knownSigner"
+        android:knownCerts="@array/config_setContactsDefaultAccountKnownSigners"
+        android:featureFlag="android.provider.new_default_account_api_enabled"/>
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing user's calendar                              -->
@@ -1080,6 +1093,52 @@
     <permission android:name="android.permission.SATELLITE_COMMUNICATION"
                 android:protectionLevel="role|signature|privileged" />
 
+    <!-- ================================== -->
+    <!-- Permissions associated with picture and sound profiles  -->
+    <!-- ================================== -->
+    <eat-comment />
+
+    <!-- @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
+         Allows an app to apply a {@link MediaQualityManager.PictureProfile} to a layer via
+         {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and, additionally, system apps via
+         {@link SurfaceControl.Transaction#setPictureProfileHandle}.
+         -->
+    <permission android:name="android.permission.APPLY_PICTURE_PROFILE"
+        android:protectionLevel="normal"
+        android:featureFlag="android.media.tv.flags.apply_picture_profiles"/>
+
+    <!-- @hide
+         Allows MediaQualityService to observe any {@link MediaQualityManager.PictureProfile}
+         applied to any layer in the system by apps via
+         {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and by system apps via
+         {@link SurfaceControl.Transaction#setPictureProfileHandle}.
+         -->
+    <permission android:name="android.permission.OBSERVE_PICTURE_PROFILES"
+        android:protectionLevel="signature|privileged"
+        android:featureFlag="android.media.tv.flags.apply_picture_profiles"/>
+
+    <!--
+        @SystemApi
+        @FlaggedApi("android.media.tv.flags.media_quality_fw")
+        Allows an application to access its picture profile from the media quality database.
+        <p> Protection level: signature|privileged|vendor privileged
+        @hide
+    -->
+    <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"
+                android:protectionLevel="signature|privileged|vendorPrivileged"
+                android:featureFlag="android.media.tv.flags.media_quality_fw"/>
+
+    <!--
+        @SystemApi
+        @FlaggedApi("android.media.tv.flags.media_quality_fw")
+        Allows an application to access its sound profile from the media quality database.
+        <p> Protection level: signature|privileged|vendor privileged
+        @hide
+    -->
+    <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"
+                android:protectionLevel="signature|privileged|vendorPrivileged"
+                android:featureFlag="android.media.tv.flags.media_quality_fw"/>
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
     <!-- ====================================================================== -->
@@ -4144,6 +4203,37 @@
     <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
         android:featureFlag="android.security.aapm_api"/>
 
+    <!-- Allows an application to read the state of the ForensicService
+         @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+         @SystemApi
+         @hide -->
+    <permission android:name="android.permission.READ_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"
+        android:protectionLevel="signature|privileged" />
+    <uses-permission android:name="android.permission.READ_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"/>
+
+    <!-- Allows an application to change the state of the ForensicService
+         @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+         @SystemApi
+         @hide -->
+    <permission android:name="android.permission.MANAGE_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"
+        android:protectionLevel="signature|privileged" />
+    <uses-permission android:name="android.permission.MANAGE_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"/>
+
+    <!-- Must be required by any ForensicEventTransportService to ensure that
+         only the system can bind to it.
+         @FlaggedApi(android.security.Flags.FLAG_AFL_API)
+         @SystemApi
+         @hide -->
+    <permission android:name="android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE"
+        android:featureFlag="android.security.afl_api"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE"
+        android:featureFlag="android.security.afl_api"/>
+
     <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.-->
     <permission android:name="android.permission.PROVISION_DEMO_DEVICE"
                 android:protectionLevel="signature|setup|knownSigner"
@@ -4991,16 +5081,16 @@
         android:protectionLevel="signature|privileged|role"
         android:featureFlag="com.android.settingslib.flags.settings_catalyst" />
 
-    <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST)
+    <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_WRITE_SYSTEM_PREFERENCE_PERMISSION_ENABLED)
          Allows an application to access the Settings Preference services to write settings
          values exposed by the system Settings app and system apps that contribute settings surfaced
          in the Settings app.
          <p>This allows the calling application to write settings values
          through the host application, agnostic of underlying storage.
-         <p>Protection Level: signature|privileged|appop - appop to be added in followup -->
+         <p>Protection Level: signature|privileged|appop -->
     <permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES"
-        android:protectionLevel="signature|privileged"
-        android:featureFlag="com.android.settingslib.flags.settings_catalyst" />
+        android:protectionLevel="signature|privileged|appop"
+        android:featureFlag="com.android.settingslib.flags.write_system_preference_permission_enabled" />
 
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
@@ -7844,7 +7934,31 @@
     <!-- @SystemApi Allows an application to access shared libraries.
          @hide -->
     <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
-                android:protectionLevel="signature|installer" />
+        android:protectionLevel="signature|installer"
+        android:featureFlag="!android.content.pm.sdk_dependency_installer" />
+
+    <!-- @SystemApi Allows an application to access shared libraries.
+         @hide -->
+    <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
+                android:protectionLevel="signature|installer|role"
+        android:featureFlag="android.content.pm.sdk_dependency_installer" />
+
+    <!-- @SystemApi Permission held by the system to allow binding to the dependency installer role
+         holder.
+         @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+         @hide -->
+    <permission android:name="android.permission.BIND_DEPENDENCY_INSTALLER"
+        android:protectionLevel="signature"
+        android:featureFlag="android.content.pm.sdk_dependency_installer" />
+
+    <!-- @SystemApi Allows an application to install shared libraries of types
+         {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or
+         {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE}.
+         @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+         @hide -->
+    <permission android:name="android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES"
+        android:protectionLevel="signature|role"
+        android:featureFlag="android.content.pm.sdk_dependency_installer" />
 
     <!-- Allows an app to log compat change usage.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -8565,27 +8679,6 @@
     <permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE"
                 android:protectionLevel="signature"/>
 
-    <!--
-        @SystemApi
-        @FlaggedApi("android.media.tv.flags.media_quality_fw")
-        Allows an application to access its picture profile from the media quality database.
-        <p> Protection level: signature|privileged|vendor privileged
-        @hide
-    -->
-    <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"
-                android:protectionLevel="signature|privileged|vendorPrivileged"
-                android:featureFlag="android.media.tv.flags.media_quality_fw"/>
-
-    <!--
-        @SystemApi
-        @FlaggedApi("android.media.tv.flags.media_quality_fw")
-        Allows an application to access its sound profile from the media quality database.
-        <p> Protection level: signature|privileged|vendor privileged
-        @hide
-    -->
-    <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE"
-                android:protectionLevel="signature|privileged|vendorPrivileged"
-                android:featureFlag="android.media.tv.flags.media_quality_fw"/>
     <!-- @SystemApi
         @FlaggedApi("android.content.pm.verification_service")
         Allows app to be the verification agent to verify packages.
diff --git a/core/res/res/drawable/notification_progress.xml b/core/res/res/drawable/notification_progress.xml
index 3a6b600..5d272fb 100644
--- a/core/res/res/drawable/notification_progress.xml
+++ b/core/res/res/drawable/notification_progress.xml
@@ -24,9 +24,9 @@
             android:segPointGap="@dimen/notification_progress_segPoint_gap">
             <segments
                 android:color="?attr/colorProgressBackgroundNormal"
-                android:dashGap="@dimen/notification_progress_segments_dash_gap"
-                android:dashWidth="@dimen/notification_progress_segments_dash_width"
-                android:width="@dimen/notification_progress_segments_height" />
+                android:height="@dimen/notification_progress_segments_height"
+                android:fadedHeight="@dimen/notification_progress_segments_faded_height"
+                android:cornerRadius="@dimen/notification_progress_segments_corner_radius"/>
             <points
                 android:color="?attr/colorProgressBackgroundNormal"
                 android:radius="@dimen/notification_progress_points_radius"
diff --git a/core/res/res/layout/list_content_simple.xml b/core/res/res/layout/list_content_simple.xml
index 6f9f1e0..961668e 100644
--- a/core/res/res/layout/list_content_simple.xml
+++ b/core/res/res/layout/list_content_simple.xml
@@ -20,5 +20,6 @@
 <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list"
     android:layout_width="match_parent" 
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:drawSelectorOnTop="false"
     />
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
new file mode 100644
index 0000000..c003820
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:minHeight="@dimen/notification_headerless_min_height"
+    android:tag="base"
+    >
+
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_2025_left_icon_size"
+        android:layout_height="@dimen/notification_2025_left_icon_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        android:visibility="gone"
+        />
+
+    <com.android.internal.widget.NotificationRowIconView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/notification_2025_icon_circle_size"
+        android:layout_height="@dimen/notification_2025_icon_circle_size"
+        android:layout_gravity="center_vertical|start"
+        android:layout_marginStart="@dimen/notification_icon_circle_start"
+        android:background="@drawable/notification_icon_circle"
+        android:padding="@dimen/notification_2025_icon_circle_padding"
+        android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size"
+        android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size"
+        />
+
+    <FrameLayout
+        android:id="@+id/alternate_expand_target"
+        android:layout_width="@dimen/notification_2025_content_margin_start"
+        android:layout_height="match_parent"
+        android:layout_gravity="start"
+        android:importantForAccessibility="no"
+        android:focusable="false"
+        />
+
+    <LinearLayout
+        android:id="@+id/notification_headerless_view_row"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+        android:orientation="horizontal"
+        >
+
+        <LinearLayout
+            android:id="@+id/notification_headerless_view_column"
+            android:layout_width="0px"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+            android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
+            android:orientation="vertical"
+            >
+
+            <NotificationTopLineView
+                android:id="@+id/notification_top_line"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minHeight="@dimen/notification_headerless_line_height"
+                android:clipChildren="false"
+                android:theme="@style/Theme.DeviceDefault.Notification"
+                >
+
+                <!--
+                NOTE: The notification_top_line_views layout contains the app_name_text.
+                In order to include the title view at the beginning, the Notification.Builder
+                has logic to hide that view whenever this title view is to be visible.
+                -->
+
+                <TextView
+                    android:id="@+id/title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                    android:ellipsize="end"
+                    android:fadingEdge="horizontal"
+                    android:singleLine="true"
+                    android:textAlignment="viewStart"
+                    android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+                    />
+
+                <include layout="@layout/notification_top_line_views" />
+
+            </NotificationTopLineView>
+
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                >
+
+                <com.android.internal.widget.NotificationVanishingFrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:minHeight="@dimen/notification_headerless_line_height"
+                    >
+                    <!-- This is the simplest way to keep this text vertically centered without
+                     gravity="center_vertical" which causes jumpiness in expansion animations. -->
+                    <include
+                        layout="@layout/notification_template_text"
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/notification_text_height"
+                        android:layout_gravity="center_vertical"
+                        android:layout_marginTop="0dp"
+                        />
+                </com.android.internal.widget.NotificationVanishingFrameLayout>
+
+                <include
+                    layout="@layout/notification_template_progress"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_headerless_line_height"
+                    />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <com.android.internal.widget.CachingIconView
+            android:id="@+id/right_icon"
+            android:layout_width="@dimen/notification_right_icon_size"
+            android:layout_height="@dimen/notification_right_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
+            android:layout_marginStart="@dimen/notification_right_icon_content_margin"
+            android:background="@drawable/notification_large_icon_outline"
+            android:clipToOutline="true"
+            android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
+            android:maxDrawableWidth="@dimen/notification_right_icon_size"
+            android:maxDrawableHeight="@dimen/notification_right_icon_size"
+            />
+
+        <LinearLayout
+            android:id="@+id/notification_buttons_column"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_alignParentEnd="true"
+            android:orientation="vertical"
+            >
+
+            <include layout="@layout/notification_close_button"
+                android:layout_width="@dimen/notification_close_button_size"
+                android:layout_height="@dimen/notification_close_button_size"
+                android:layout_gravity="end"
+                android:layout_marginEnd="20dp"
+                />
+
+            <FrameLayout
+                android:id="@+id/expand_button_touch_container"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:minWidth="@dimen/notification_content_margin_end"
+                >
+
+                <include layout="@layout/notification_expand_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical|end"
+                    />
+
+            </FrameLayout>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml
new file mode 100644
index 0000000..b7fe454
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_header.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- extends RelativeLayout -->
+<NotificationHeaderView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_header"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_2025_header_height"
+    android:layout_marginBottom="@dimen/notification_header_margin_bottom"
+    android:clipChildren="false"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:theme="@style/Theme.DeviceDefault.Notification"
+    android:importantForAccessibility="no"
+    >
+
+    <ImageView
+        android:id="@+id/left_icon"
+        android:layout_width="@dimen/notification_2025_left_icon_size"
+        android:layout_height="@dimen/notification_2025_left_icon_size"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_marginStart="@dimen/notification_left_icon_start"
+        android:background="@drawable/notification_large_icon_outline"
+        android:clipToOutline="true"
+        android:importantForAccessibility="no"
+        android:scaleType="centerCrop"
+        android:visibility="gone"
+        />
+
+    <com.android.internal.widget.NotificationRowIconView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/notification_2025_icon_circle_size"
+        android:layout_height="@dimen/notification_2025_icon_circle_size"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_marginStart="@dimen/notification_icon_circle_start"
+        android:background="@drawable/notification_icon_circle"
+        android:padding="@dimen/notification_2025_icon_circle_padding"
+        android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size"
+        android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size"
+        />
+
+    <!-- extends ViewGroup -->
+    <NotificationTopLineView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/notification_top_line"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_toStartOf="@id/notification_buttons_column"
+        android:layout_alignWithParentIfMissing="true"
+        android:clipChildren="false"
+        android:gravity="center_vertical"
+        android:paddingStart="@dimen/notification_2025_content_margin_start"
+        android:theme="@style/Theme.DeviceDefault.Notification"
+        >
+
+        <include layout="@layout/notification_top_line_views" />
+
+    </NotificationTopLineView>
+
+    <FrameLayout
+        android:id="@+id/alternate_expand_target"
+        android:layout_width="@dimen/notification_2025_content_margin_start"
+        android:layout_height="match_parent"
+        android:layout_alignParentStart="true"
+        android:importantForAccessibility="no"
+        android:focusable="false"
+        />
+
+    <LinearLayout
+        android:id="@+id/notification_buttons_column"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:orientation="vertical"
+        >
+
+        <include layout="@layout/notification_close_button"
+            android:layout_width="@dimen/notification_close_button_size"
+            android:layout_height="@dimen/notification_close_button_size"
+            android:layout_gravity="end"
+            android:layout_marginEnd="20dp"
+            />
+
+        <include layout="@layout/notification_expand_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_centerVertical="true"
+            />
+
+    </LinearLayout>
+
+</NotificationHeaderView>
diff --git a/core/res/res/values-night/colors_dynamic.xml b/core/res/res/values-night/colors_dynamic.xml
new file mode 100644
index 0000000..7e95ff4
--- /dev/null
+++ b/core/res/res/values-night/colors_dynamic.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Colors specific to Material themes. -->
+<resources>
+    <color name="materialColorBackground">@color/system_background_dark</color>
+    <color name="materialColorControlActivated">@color/system_control_activated_dark</color>
+    <color name="materialColorControlHighlight">@color/system_control_highlight_dark</color>
+    <color name="materialColorControlNormal">@color/system_control_normal_dark</color>
+    <color name="materialColorError">@color/system_error_dark</color>
+    <color name="materialColorErrorContainer">@color/system_error_container_dark</color>
+    <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</color>
+    <color name="materialColorInversePrimary">@color/system_inverse_primary_dark</color>
+    <color name="materialColorInverseSurface">@color/system_inverse_surface_dark</color>
+    <color name="materialColorOnBackground">@color/system_on_background_dark</color>
+    <color name="materialColorOnError">@color/system_on_error_dark</color>
+    <color name="materialColorOnErrorContainer">@color/system_on_error_container_dark</color>
+    <color name="materialColorOnPrimary">@color/system_on_primary_dark</color>
+    <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</color>
+    <color name="materialColorOnSecondary">@color/system_on_secondary_dark</color>
+    <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</color>
+    <color name="materialColorOnSurface">@color/system_on_surface_dark</color>
+    <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</color>
+    <color name="materialColorOnTertiary">@color/system_on_tertiary_dark</color>
+    <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</color>
+    <color name="materialColorOutline">@color/system_outline_dark</color>
+    <color name="materialColorOutlineVariant">@color/system_outline_variant_dark</color>
+    <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</color>
+    <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</color>
+    <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</color>
+    <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</color>
+    <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</color>
+    <color name="materialColorPrimary">@color/system_primary_dark</color>
+    <color name="materialColorPrimaryContainer">@color/system_primary_container_dark</color>
+    <color name="materialColorScrim">@color/system_scrim_dark</color>
+    <color name="materialColorSecondary">@color/system_secondary_dark</color>
+    <color name="materialColorSecondaryContainer">@color/system_secondary_container_dark</color>
+    <color name="materialColorShadow">@color/system_shadow_dark</color>
+    <color name="materialColorSurface">@color/system_surface_dark</color>
+    <color name="materialColorSurfaceBright">@color/system_surface_bright_dark</color>
+    <color name="materialColorSurfaceContainer">@color/system_surface_container_dark</color>
+    <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</color>
+    <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</color>
+    <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</color>
+    <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</color>
+    <color name="materialColorSurfaceDim">@color/system_surface_dim_dark</color>
+    <color name="materialColorSurfaceTint">@color/system_surface_tint_dark</color>
+    <color name="materialColorSurfaceVariant">@color/system_surface_variant_dark</color>
+    <color name="materialColorTertiary">@color/system_tertiary_dark</color>
+    <color name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</color>
+    <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</color>
+    <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</color>
+    <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</color>
+    <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</color>
+    <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</color>
+    <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+    <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+    <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+    <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+    <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+    <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+    <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+    <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+    <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+    <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+    <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+    <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+    <color name="customColorBrandA">@color/system_brand_a_dark</color>
+    <color name="customColorBrandB">@color/system_brand_b_dark</color>
+    <color name="customColorBrandC">@color/system_brand_c_dark</color>
+    <color name="customColorBrandD">@color/system_brand_d_dark</color>
+    <color name="customColorClockHour">@color/system_clock_hour_dark</color>
+    <color name="customColorClockMinute">@color/system_clock_minute_dark</color>
+    <color name="customColorClockSecond">@color/system_clock_second_dark</color>
+    <color name="customColorOnShadeActive">@color/system_on_shade_active_dark</color>
+    <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</color>
+    <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</color>
+    <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</color>
+    <color name="customColorOnThemeApp">@color/system_on_theme_app_dark</color>
+    <color name="customColorOverviewBackground">@color/system_overview_background_dark</color>
+    <color name="customColorShadeActive">@color/system_shade_active_dark</color>
+    <color name="customColorShadeDisabled">@color/system_shade_disabled_dark</color>
+    <color name="customColorShadeInactive">@color/system_shade_inactive_dark</color>
+    <color name="customColorThemeApp">@color/system_theme_app_dark</color>
+    <color name="customColorThemeAppRing">@color/system_theme_app_ring_dark</color>
+    <color name="customColorThemeNotif">@color/system_theme_notif_dark</color>
+    <color name="customColorUnderSurface">@color/system_under_surface_dark</color>
+    <color name="customColorWeatherTemp">@color/system_weather_temp_dark</color>
+    <color name="customColorWidgetBackground">@color/system_widget_background_dark</color>
+</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 4d2085bb..7ac1759 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -238,16 +238,16 @@
         <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
         <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
         <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
         <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
         <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
         <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
+        <item name="materialColorInversePrimary">@color/system_primary_light</item>
         <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+        <item name="materialColorInverseSurface">@color/system_surface_light</item>
         <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
         <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e6dedce..f6590b1 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1218,155 +1218,132 @@
              it prevent any 'false' in any of its children. -->
         <attr name="forceDarkAllowed" format="boolean" />
 
-        <!-- A lower-emphasized variant of the color on the fixed secondary branding color. @hide
-             -->
-        <attr name="materialColorOnSecondaryFixedVariant" format="color"/>
-        <!-- A lower-emphasized variant of the color on the fixed tertiary branding color. @hide
-             -->
-        <attr name="materialColorOnTertiaryFixedVariant" format="color"/>
-        <!-- The container color of surface the most lowered. @hide -->
-        <attr name="materialColorSurfaceContainerLowest" format="color"/>
-        <!-- A lower-emphasized variant of the color on the fixed primary branding color. @hide -->
-        <attr name="materialColorOnPrimaryFixedVariant" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             the secondary container color. @hide -->
-        <attr name="materialColorOnSecondaryContainer" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             the tertiary container color. @hide -->
-        <attr name="materialColorOnTertiaryContainer" format="color"/>
-        <!-- The container color of surface slightly lowered, which replaces the previous surface
-             at elevation level 1. @hide -->
-        <attr name="materialColorSurfaceContainerLow" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             the primary container color. @hide -->
-        <attr name="materialColorOnPrimaryContainer" format="color"/>
-        <!-- A stronger, more emphasized variant of the fixed secondary branding color. @hide -->
-        <attr name="materialColorSecondaryFixedDim" format="color"/>
-        <!-- A tonal variation of the on error color that passes accessibility guidelines for
-             text/iconography when drawn on top of error container. @hide -->
-        <attr name="materialColorOnErrorContainer" format="color"/>
-        <!-- The color text/iconography when drawn on top of the fixed secondary branding color.
-             @hide -->
-        <attr name="materialColorOnSecondaryFixed" format="color"/>
-        <!-- The "on surface" inverse color, useful for inverted backgrounds. @hide -->
-        <attr name="materialColorOnSurfaceInverse" format="color"/>
-        <!-- A stronger, more emphasized variant of the fixed tertiary branding color. @hide -->
-        <attr name="materialColorTertiaryFixedDim" format="color"/>
-        <!-- The color text/iconography when drawn on top of the fixed tertiary branding color.
-             @hide -->
-        <attr name="materialColorOnTertiaryFixed" format="color"/>
-        <!-- A stronger, more emphasized variant of the fixed primary branding color. @hide -->
-        <attr name="materialColorPrimaryFixedDim" format="color"/>
-        <!-- A tonal variation of the secondary color suitable for background color of container
-             views. @hide -->
-        <attr name="materialColorSecondaryContainer" format="color"/>
-        <!-- A tonal variation of the error color suitable for background color of container views.
-             @hide -->
-        <attr name="materialColorErrorContainer" format="color"/>
-        <!-- The color text/iconography when drawn on top of the fixed primary branding color.
-             @hide -->
-        <attr name="materialColorOnPrimaryFixed" format="color"/>
-        <!-- The inverse color of colorPrimary. @hide -->
-        <attr name="materialColorPrimaryInverse" format="color"/>
-        <!-- A secondary branding color for the app, which stays the same between light and dark
-             themes. @hide -->
-        <attr name="materialColorSecondaryFixed" format="color"/>
-        <!-- The surface inverse color, useful for inverted backgrounds. @hide -->
-        <attr name="materialColorSurfaceInverse" format="color"/>
-        <!-- A tonal variation of the surface color. @hide -->
-        <attr name="materialColorSurfaceVariant" format="color"/>
-        <!-- A tonal variation of the tertiary color suitable for background color of container
-             views. @hide -->
-        <attr name="materialColorTertiaryContainer" format="color"/>
-        <!-- A tertiary branding color for the app, which stays the same between light and dark
-             themes. @hide -->
-        <attr name="materialColorTertiaryFixed" format="color"/>
-        <!-- A tonal variation of the primary color suitable for background color of container
-             views. @hide -->
-        <attr name="materialColorPrimaryContainer" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             background. @hide -->
-        <attr name="materialColorOnBackground" format="color"/>
-        <!-- A primary branding color for the app, which stays the same between light and dark
-             themes. @hide -->
-        <attr name="materialColorPrimaryFixed" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             secondary. @hide -->
-        <attr name="materialColorOnSecondary" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             tertiary. @hide -->
-        <attr name="materialColorOnTertiary" format="color"/>
-        <!-- The surface color which always stay the dimmest in either dark or light theme. @hide
-             -->
-        <attr name="materialColorSurfaceDim" format="color"/>
-        <!-- The surface color which always stay the brightest in either dark or light theme. @hide
-             -->
-        <attr name="materialColorSurfaceBright" format="color"/>
-        <!-- The secondary branding color for the app, usually a bright complement to the primary
-             branding color. @hide -->
-        <attr name="materialColorSecondary" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             error. @hide -->
-        <attr name="materialColorOnError" format="color"/>
-        <!-- The color of surfaces such as cards, sheets, menus. @hide -->
-        <attr name="materialColorSurface" format="color"/>
-        <!-- The container color of surface slightly elevated, which replaces the previous surface
-             at elevation level 3. @hide -->
-        <attr name="materialColorSurfaceContainerHigh" format="color"/>
-        <!-- The tertiary branding color for the app, usually a bright complement to the primary
-             branding color. @hide -->
-        <attr name="materialColorTertiary" format="color"/>
-        <!-- The container color of surface the most elevated, which replaces the previous surface
-             variant. @hide -->
-        <attr name="materialColorSurfaceContainerHighest" format="color"/>
-        <!-- A tonal variation of the on surface color that passes accessibility guidelines for
-             text/iconography when drawn on top of surface variant. @hide -->
-        <attr name="materialColorOnSurfaceVariant" format="color"/>
-        <!-- A color meant to be used in element outlines. @hide -->
-        <attr name="materialColorOutline" format="color"/>
-        <!-- A color meant to be used in element outlines on the surface-variant color. @hide -->
-        <attr name="materialColorOutlineVariant" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             primary. @hide -->
-        <attr name="materialColorOnPrimary" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of
-             surface. @hide -->
-        <attr name="materialColorOnSurface" format="color"/>
-        <!-- The container color of surface, which replaces the previous surface at elevation level
-             2. @hide -->
-        <attr name="materialColorSurfaceContainer" format="color"/>
-        <!-- The container color of surface, which replaces the previous surface at elevation level
-             2. @hide -->
-        <attr name="materialColorSurfaceContainer" format="color"/>
-         <!-- The primary branding color for the app. By default, this is the color applied to the
-             action bar background. @hide -->
-        <attr name="materialColorPrimary" format="color"/>
-        <!-- The secondary branding color for the app, usually a bright complement to the primary
-             branding color. @hide -->
-        <attr name="materialColorSecondary" format="color"/>
-        <!-- A color that passes accessibility guidelines for text/iconography when drawn on top
-             of tertiary. @hide -->
-        <attr name="materialColorTertiary" format="color"/>
-        <!-- The error color for the app, intended to draw attention to error conditions. @hide -->
-        <attr name="materialColorError" format="color"/>
+        <!-- Dynamic Tokens -->
 
-        <!-- System Custom Tokens-->
         <!-- @hide -->
-        <attr name="customColorWidgetBackground" format="color"/>
+        <attr name="materialColorBackground" format="color"/>
         <!-- @hide -->
-        <attr name="customColorClockHour" format="color"/>
+        <attr name="materialColorControlActivated" format="color"/>
         <!-- @hide -->
-        <attr name="customColorClockMinute" format="color"/>
+        <attr name="materialColorControlHighlight" format="color"/>
         <!-- @hide -->
-        <attr name="customColorClockSecond" format="color"/>
+        <attr name="materialColorControlNormal" format="color"/>
         <!-- @hide -->
-        <attr name="customColorThemeApp" format="color"/>
+        <attr name="materialColorError" format="color"/>
         <!-- @hide -->
-        <attr name="customColorOnThemeApp" format="color"/>
+        <attr name="materialColorErrorContainer" format="color"/>
         <!-- @hide -->
-        <attr name="customColorThemeAppRing" format="color"/>
+        <attr name="materialColorInverseOnSurface" format="color"/>
         <!-- @hide -->
-        <attr name="customColorThemeNotif" format="color"/>
+        <attr name="materialColorInversePrimary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorInverseSurface" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnBackground" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnError" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnErrorContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnPrimary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnPrimaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSecondary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSecondaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSurface" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSurfaceVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnTertiary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnTertiaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOutline" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOutlineVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPaletteKeyColorNeutral" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPaletteKeyColorNeutralVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPaletteKeyColorPrimary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPaletteKeyColorSecondary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPaletteKeyColorTertiary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPrimary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPrimaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorScrim" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSecondary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSecondaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorShadow" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurface" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceBright" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceContainerHigh" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceContainerHighest" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceContainerLow" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceContainerLowest" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceDim" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceTint" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSurfaceVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTertiary" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTertiaryContainer" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTextHintInverse" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTextPrimaryInverse" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTextPrimaryInverseDisableOnly" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTextSecondaryAndTertiaryInverse" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTextSecondaryAndTertiaryInverseDisabled" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnPrimaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnPrimaryFixedVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSecondaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnSecondaryFixedVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnTertiaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorOnTertiaryFixedVariant" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPrimaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorPrimaryFixedDim" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSecondaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorSecondaryFixedDim" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTertiaryFixed" format="color"/>
+        <!-- @hide -->
+        <attr name="materialColorTertiaryFixedDim" format="color"/>
         <!-- @hide -->
         <attr name="customColorBrandA" format="color"/>
         <!-- @hide -->
@@ -1376,23 +1353,41 @@
         <!-- @hide -->
         <attr name="customColorBrandD" format="color"/>
         <!-- @hide -->
-        <attr name="customColorUnderSurface" format="color"/>
+        <attr name="customColorClockHour" format="color"/>
         <!-- @hide -->
-        <attr name="customColorShadeActive" format="color"/>
+        <attr name="customColorClockMinute" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorClockSecond" format="color"/>
         <!-- @hide -->
         <attr name="customColorOnShadeActive" format="color"/>
         <!-- @hide -->
         <attr name="customColorOnShadeActiveVariant" format="color"/>
         <!-- @hide -->
-        <attr name="customColorShadeInactive" format="color"/>
-        <!-- @hide -->
         <attr name="customColorOnShadeInactive" format="color"/>
         <!-- @hide -->
         <attr name="customColorOnShadeInactiveVariant" format="color"/>
         <!-- @hide -->
-        <attr name="customColorShadeDisabled" format="color"/>
+        <attr name="customColorOnThemeApp" format="color"/>
         <!-- @hide -->
         <attr name="customColorOverviewBackground" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorShadeActive" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorShadeDisabled" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorShadeInactive" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorThemeApp" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorThemeAppRing" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorThemeNotif" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorUnderSurface" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorWeatherTemp" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorWidgetBackground" format="color"/>
 
     </declare-styleable>
 
@@ -7753,14 +7748,14 @@
     <!-- Used to config the segments of a NotificationProgressDrawable. -->
     <!-- @hide internal use only -->
     <declare-styleable name="NotificationProgressDrawableSegments">
-        <!-- Width of the stroke. -->
-        <attr name="width" />
-        <!-- Default color of the stroke. -->
+        <!-- Height of the solid segments -->
+        <attr name="height" />
+        <!-- Height of the faded segments -->
+        <attr name="fadedHeight" format="dimension"/>
+        <!-- Corner radius of the segment rect. -->
+        <attr name="cornerRadius" format="dimension" />
+        <!-- Default color of the segment. -->
         <attr name="color" />
-        <!-- Length of a dash in the stroke for the dashed segments. -->
-        <attr name="dashWidth" />
-        <!-- Gap between dashes in the stroke for the dashed segments. -->
-        <attr name="dashGap" />
     </declare-styleable>
 
     <!-- Used to config the points of a NotificationProgressDrawable. -->
@@ -7771,7 +7766,7 @@
         <!-- Inset of the point icon or rect. -->
         <attr name="inset" />
         <!-- Corner radius of the point rect. -->
-        <attr name="cornerRadius" format="dimension" />
+        <attr name="cornerRadius"/>
         <!-- Default color of the point rect. -->
         <attr name="color" />
     </declare-styleable>
@@ -10285,22 +10280,25 @@
     </declare-styleable>
 
     <!-- @hide -->
+    <attr name="modifierState">
+        <flag name="META" value="0x10000" />
+        <flag name="CTRL" value="0x1000" />
+        <flag name="ALT" value="0x02" />
+        <flag name="SHIFT" value="0x1" />
+        <flag name="SYM" value="0x4" />
+        <flag name="FUNCTION" value="0x8" />
+        <flag name="CAPS_LOCK" value="0x100000" />
+        <flag name="NUM_LOCK" value="0x200000" />
+        <flag name="SCROLL_LOCK" value="0x400000" />
+    </attr>
+
+    <!-- @hide -->
     <declare-styleable name="HardwareDefinedShortcut">
         <attr name="keycode" />
         <!-- The values are taken from public constants for modifier state defined in
              {@see KeyEvent.java}. Here we allow multiple modifier flags as value, since this
              represents the modifier state -->
-        <attr name="modifierState">
-            <flag name="META" value="0x10000" />
-            <flag name="CTRL" value="0x1000" />
-            <flag name="ALT" value="0x02" />
-            <flag name="SHIFT" value="0x1" />
-            <flag name="SYM" value="0x4" />
-            <flag name="FUNCTION" value="0x8" />
-            <flag name="CAPS_LOCK" value="0x100000" />
-            <flag name="NUM_LOCK" value="0x200000" />
-            <flag name="SCROLL_LOCK" value="0x400000" />
-        </attr>
+        <attr name="modifierState" />
         <attr name="outKeycode" />
     </declare-styleable>
 
@@ -10309,6 +10307,11 @@
         <attr name="keycode" />
     </declare-styleable>
 
+    <declare-styleable name="Bookmark">
+        <attr name="keycode" />
+        <attr name="modifierState" />
+    </declare-styleable>
+
     <declare-styleable name="MediaRouteButton">
         <!-- This drawable is a state list where the "activated" state
              indicates active media routing. Non-activated indicates
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 41dec37..7ef5394 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1855,13 +1855,23 @@
          {@link android.R.styleable#AndroidManifestProcess process} tag, or to an
          {@link android.R.styleable#AndroidManifestApplication application} tag (to supply
          a default setting for all application components). -->
-    <attr name="memtagMode">
+     <attr name="memtagMode">
        <enum name="default" value="-1" />
        <enum name="off" value="0" />
        <enum name="async" value="1" />
        <enum name="sync" value="2" />
     </attr>
 
+    <!-- This attribute will be used to override app compatibility mode on 16 KB devices.
+         If set to enabled, Natives lib will be extracted from APK if they are not page aligned on
+         16 KB device. 4 KB natives libs will be loaded app-compat mode if they are eligible.
+         @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+    <attr name="pageSizeCompat">
+        <enum name="enabled" value="5" />
+        <enum name="disabled" value="6" />
+    </attr>
+
+
     <!-- Attribution tag to be used for permission sub-attribution if a
       permission is checked in  {@link android.content.Context#sendBroadcast(Intent, String)}.
       Multiple tags can be specified separated by '|'.
@@ -2212,6 +2222,9 @@
 
         <attr name="memtagMode" />
 
+        <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+        <attr name="pageSizeCompat" />
+
         <!-- If {@code true} enables automatic zero initialization of all native heap
              allocations. -->
         <attr name="nativeHeapZeroInitialized" format="boolean" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index f5bb554..13dd4a3 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -238,393 +238,319 @@
 
     <color name="conversation_important_highlight">#F9AB00</color>
 
-    <!--Lightest shade of the Primary color used by the system. White.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Lightest shade of the Primary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_0">#FFFFFF</color>
-    <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_10">#FEFBFF</color>
-    <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_50">#EEF0FF</color>
-    <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_100">#D9E2FF</color>
-    <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_200">#B0C6FF</color>
-    <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_300">#94AAE4</color>
-    <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_400">#7A90C8</color>
-    <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_500">#6076AC</color>
-    <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_600">#475D92</color>
-    <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_700">#2F4578</color>
-    <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_800">#152E60</color>
-    <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_900">#001945</color>
-    <!--Darkest shade of the Primary color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Darkest shade of the Primary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent1_1000">#000000</color>
-
-    <!--Lightest shade of the Secondary color used by the system. White.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Lightest shade of the Secondary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_0">#FFFFFF</color>
-    <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_10">#FEFBFF</color>
-    <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_50">#EEF0FF</color>
-    <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_100">#DCE2F9</color>
-    <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_200">#C0C6DC</color>
-    <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_300">#A4ABC1</color>
-    <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_400">#8A90A5</color>
-    <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_500">#70778B</color>
-    <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_600">#575E71</color>
-    <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_700">#404659</color>
-    <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_800">#2A3042</color>
-    <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_900">#151B2C</color>
-    <!--Darkest shade of the Secondary color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Darkest shade of the Secondary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent2_1000">#000000</color>
-
-    <!--Lightest shade of the Tertiary color used by the system. White.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Lightest shade of the Tertiary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_0">#FFFFFF</color>
-    <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_10">#FFFBFF</color>
-    <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_50">#FFEBFA</color>
-    <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_100">#FDD7FA</color>
-    <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_200">#E0BBDD</color>
-    <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_300">#C3A0C1</color>
-    <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_400">#A886A6</color>
-    <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_500">#8C6D8C</color>
-    <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_600">#725572</color>
-    <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_700">#593D59</color>
-    <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_800">#412742</color>
-    <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_900">#2A122C</color>
-    <!--Darkest shade of the Tertiary color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Darkest shade of the Tertiary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_accent3_1000">#000000</color>
-
-    <!--Lightest shade of the Neutral color used by the system. White.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Lightest shade of the Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_0">#FFFFFF</color>
-    <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_10">#FEFBFF</color>
-    <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_50">#F1F0F7</color>
-    <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_100">#E2E2E9</color>
-    <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_200">#C6C6CD</color>
-    <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_300">#ABABB1</color>
-    <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_400">#909097</color>
-    <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_500">#76777D</color>
-    <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_600">#5D5E64</color>
-    <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_700">#45464C</color>
-    <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_800">#2F3036</color>
-    <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_900">#1A1B20</color>
-    <!--Darkest shade of the Neutral color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Darkest shade of the Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral1_1000">#000000</color>
-
-    <!--Lightest shade of the Secondary Neutral color used by the system. White.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Lightest shade of the Secondary Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_0">#FFFFFF</color>
-    <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_10">#FEFBFF</color>
-    <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_50">#F0F0FA</color>
-    <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_100">#E1E2EC</color>
-    <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_200">#C5C6D0</color>
-    <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_300">#A9ABB4</color>
-    <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_400">#8F9099</color>
-    <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_500">#757780</color>
-    <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_600">#5C5E67</color>
-    <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_700">#44464F</color>
-    <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_800">#2E3038</color>
-    <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_900">#191B23</color>
-    <!--Darkest shade of the Secondary Neutral color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs.-->
+    <!--Darkest shade of the Secondary Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_neutral2_1000">#000000</color>
-
-    <!-- Lightest shade of the error color used by the system. White.
- This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_0">#ffffff</color>
-    <!-- Shade of the error system color at 99% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_10">#FFFBF9</color>
-    <!-- Shade of the error system color at 95% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_50">#FCEEEE</color>
-    <!-- Shade of the error system color at 90% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_100">#F9DEDC</color>
-    <!-- Shade of the error system color at 80% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_200">#F2B8B5</color>
-    <!-- Shade of the error system color at 70% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_300">#EC928E</color>
-    <!-- Shade of the error system color at 60% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_400">#E46962</color>
-    <!-- Shade of the error system color at 49% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_500">#DC362E</color>
-    <!-- Shade of the error system color at 40% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_600">#B3261E</color>
-    <!-- Shade of the error system color at 30% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_700">#8C1D18</color>
-    <!-- Shade of the error system color at 20% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_800">#601410</color>
-    <!-- Shade of the error system color at 10% perceptual luminance (L* in L*a*b* color space).
-     This value can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_error_900">#410E0B</color>
-    <!-- Darkest shade of the error color used by the system. Black.
-     This value can be overlaid at runtime by OverlayManager RROs. -->
+    <!--Lightest shade of the Error color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_0">#FFFFFF</color>
+    <!--Shade of the Error system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_10">#FFFBFF</color>
+    <!--Shade of the Error system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_50">#FFEDEA</color>
+    <!--Shade of the Error system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_100">#FFDAD6</color>
+    <!--Shade of the Error system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_200">#FFB4AB</color>
+    <!--Shade of the Error system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_300">#FF897D</color>
+    <!--Shade of the Error system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_400">#FF5449</color>
+    <!--Shade of the Error system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_500">#DE3730</color>
+    <!--Shade of the Error system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_600">#BA1A1A</color>
+    <!--Shade of the Error system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_700">#93000A</color>
+    <!--Shade of the Error system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_800">#690005</color>
+    <!--Shade of the Error system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.-->
+    <color name="system_error_900">#410002</color>
+    <!--Darkest shade of the Error color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.-->
     <color name="system_error_1000">#000000</color>
 
-    <!-- Colors used in Android system, from design system.
-     These values can be overlaid at runtime by OverlayManager RROs. -->
-    <color name="system_primary_container_light">#D9E2FF</color>
-    <color name="system_on_primary_container_light">#001945</color>
-    <color name="system_primary_light">#475D92</color>
-    <color name="system_on_primary_light">#FFFFFF</color>
-    <color name="system_secondary_container_light">#DCE2F9</color>
-    <color name="system_on_secondary_container_light">#151B2C</color>
-    <color name="system_secondary_light">#575E71</color>
-    <color name="system_on_secondary_light">#FFFFFF</color>
-    <color name="system_tertiary_container_light">#FDD7FA</color>
-    <color name="system_on_tertiary_container_light">#2A122C</color>
-    <color name="system_tertiary_light">#725572</color>
-    <color name="system_on_tertiary_light">#FFFFFF</color>
-    <color name="system_background_light">#FAF8FF</color>
+    <!--Colors used in Android system, from design system. These values can be overlaid at runtime by OverlayManager RROs.--><color name="system_background_light">#FAF8FF</color>
+    <color name="system_control_activated_light">#D9E2FF</color>
+    <color name="system_control_highlight_light">#000000</color>
+    <color name="system_control_normal_light">#44464F</color>
+    <color name="system_error_light">#BA1A1A</color>
+    <color name="system_error_container_light">#FFDAD6</color>
+    <color name="system_inverse_on_surface_light">#F1F0F7</color>
+    <color name="system_inverse_primary_light">#B0C6FF</color>
+    <color name="system_inverse_surface_light">#2F3036</color>
     <color name="system_on_background_light">#1A1B20</color>
-    <color name="system_surface_light">#FAF8FF</color>
+    <color name="system_on_error_light">#FFFFFF</color>
+    <color name="system_on_error_container_light">#93000A</color>
+    <color name="system_on_primary_light">#FFFFFF</color>
+    <color name="system_on_primary_container_light">#2F4578</color>
+    <color name="system_on_secondary_light">#FFFFFF</color>
+    <color name="system_on_secondary_container_light">#404659</color>
     <color name="system_on_surface_light">#1A1B20</color>
-    <color name="system_surface_container_low_light">#F4F3FA</color>
-    <color name="system_surface_container_lowest_light">#FFFFFF</color>
-    <color name="system_surface_container_light">#EEEDF4</color>
-    <color name="system_surface_container_high_light">#E8E7EF</color>
-    <color name="system_surface_container_highest_light">#E2E2E9</color>
-    <color name="system_surface_bright_light">#FAF8FF</color>
-    <color name="system_surface_dim_light">#DAD9E0</color>
-    <color name="system_surface_variant_light">#E1E2EC</color>
     <color name="system_on_surface_variant_light">#44464F</color>
+    <color name="system_on_tertiary_light">#FFFFFF</color>
+    <color name="system_on_tertiary_container_light">#593D59</color>
     <color name="system_outline_light">#757780</color>
     <color name="system_outline_variant_light">#C5C6D0</color>
-    <color name="system_error_light">#BA1A1A</color>
-    <color name="system_on_error_light">#FFFFFF</color>
-    <color name="system_error_container_light">#FFDAD6</color>
-    <color name="system_on_error_container_light">#410002</color>
-    <color name="system_control_activated_light">#D9E2FF</color>
-    <color name="system_control_normal_light">#44464F</color>
-    <color name="system_control_highlight_light">#000000</color>
-<color name="system_text_primary_inverse_light">#E2E2E9</color>
-    <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color>
-    <color name="system_text_primary_inverse_disable_only_light">#E2E2E9</color>
-    <color name="system_text_secondary_and_tertiary_inverse_disabled_light">#E2E2E9</color>
-    <color name="system_text_hint_inverse_light">#E2E2E9</color>
+    <color name="system_palette_key_color_neutral_light">#76777D</color>
+    <color name="system_palette_key_color_neutral_variant_light">#757780</color>
     <color name="system_palette_key_color_primary_light">#6076AC</color>
     <color name="system_palette_key_color_secondary_light">#70778B</color>
     <color name="system_palette_key_color_tertiary_light">#8C6D8C</color>
-    <color name="system_palette_key_color_neutral_light">#76777D</color>
-    <color name="system_palette_key_color_neutral_variant_light">#757780</color>
-    <color name="system_primary_container_dark">#2F4578</color>
-    <color name="system_on_primary_container_dark">#D9E2FF</color>
-    <color name="system_primary_dark">#B0C6FF</color>
-    <color name="system_on_primary_dark">#152E60</color>
-    <color name="system_secondary_container_dark">#404659</color>
-    <color name="system_on_secondary_container_dark">#DCE2F9</color>
-    <color name="system_secondary_dark">#C0C6DC</color>
-    <color name="system_on_secondary_dark">#2A3042</color>
-    <color name="system_tertiary_container_dark">#593D59</color>
-    <color name="system_on_tertiary_container_dark">#FDD7FA</color>
-    <color name="system_tertiary_dark">#E0BBDD</color>
-    <color name="system_on_tertiary_dark">#412742</color>
+    <color name="system_primary_light">#475D92</color>
+    <color name="system_primary_container_light">#D9E2FF</color>
+    <color name="system_scrim_light">#000000</color>
+    <color name="system_secondary_light">#575E71</color>
+    <color name="system_secondary_container_light">#DCE2F9</color>
+    <color name="system_shadow_light">#000000</color>
+    <color name="system_surface_light">#FAF8FF</color>
+    <color name="system_surface_bright_light">#FAF8FF</color>
+    <color name="system_surface_container_light">#EEEDF4</color>
+    <color name="system_surface_container_high_light">#E8E7EF</color>
+    <color name="system_surface_container_highest_light">#E2E2E9</color>
+    <color name="system_surface_container_low_light">#F4F3FA</color>
+    <color name="system_surface_container_lowest_light">#FFFFFF</color>
+    <color name="system_surface_dim_light">#DAD9E0</color>
+    <color name="system_surface_tint_light">#475D92</color>
+    <color name="system_surface_variant_light">#E1E2EC</color>
+    <color name="system_tertiary_light">#725572</color>
+    <color name="system_tertiary_container_light">#FDD7FA</color>
+    <color name="system_text_hint_inverse_light">#E2E2E9</color>
+    <color name="system_text_primary_inverse_light">#E2E2E9</color>
+    <color name="system_text_primary_inverse_disable_only_light">#E2E2E9</color>
+    <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color>
+    <color name="system_text_secondary_and_tertiary_inverse_disabled_light">#E2E2E9</color>
     <color name="system_background_dark">#121318</color>
+    <color name="system_control_activated_dark">#2F4578</color>
+    <color name="system_control_highlight_dark">#FFFFFF</color>
+    <color name="system_control_normal_dark">#C5C6D0</color>
+    <color name="system_error_dark">#FFB4AB</color>
+    <color name="system_error_container_dark">#93000A</color>
+    <color name="system_inverse_on_surface_dark">#2F3036</color>
+    <color name="system_inverse_primary_dark">#475D92</color>
+    <color name="system_inverse_surface_dark">#E2E2E9</color>
     <color name="system_on_background_dark">#E2E2E9</color>
-    <color name="system_surface_dark">#121318</color>
+    <color name="system_on_error_dark">#690005</color>
+    <color name="system_on_error_container_dark">#FFDAD6</color>
+    <color name="system_on_primary_dark">#152E60</color>
+    <color name="system_on_primary_container_dark">#D9E2FF</color>
+    <color name="system_on_secondary_dark">#2A3042</color>
+    <color name="system_on_secondary_container_dark">#DCE2F9</color>
     <color name="system_on_surface_dark">#E2E2E9</color>
-    <color name="system_surface_container_low_dark">#1A1B20</color>
-    <color name="system_surface_container_lowest_dark">#0C0E13</color>
-    <color name="system_surface_container_dark">#1E1F25</color>
-    <color name="system_surface_container_high_dark">#282A2F</color>
-    <color name="system_surface_container_highest_dark">#33343A</color>
-    <color name="system_surface_bright_dark">#38393F</color>
-    <color name="system_surface_dim_dark">#121318</color>
-    <color name="system_surface_variant_dark">#44464F</color>
     <color name="system_on_surface_variant_dark">#C5C6D0</color>
+    <color name="system_on_tertiary_dark">#412742</color>
+    <color name="system_on_tertiary_container_dark">#FDD7FA</color>
     <color name="system_outline_dark">#8F9099</color>
     <color name="system_outline_variant_dark">#44464F</color>
-    <color name="system_error_dark">#FFB4AB</color>
-    <color name="system_on_error_dark">#690005</color>
-    <color name="system_error_container_dark">#93000A</color>
-    <color name="system_on_error_container_dark">#FFDAD6</color>
-    <color name="system_control_activated_dark">#2F4578</color>
-    <color name="system_control_normal_dark">#C5C6D0</color>
-    <color name="system_control_highlight_dark">#FFFFFF</color>
-    <color name="system_text_primary_inverse_dark">#1A1B20</color>
-    <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color>
-    <color name="system_text_primary_inverse_disable_only_dark">#1A1B20</color>
-    <color name="system_text_secondary_and_tertiary_inverse_disabled_dark">#1A1B20</color>
-    <color name="system_text_hint_inverse_dark">#1A1B20</color>
+    <color name="system_palette_key_color_neutral_dark">#76777D</color>
+    <color name="system_palette_key_color_neutral_variant_dark">#757780</color>
     <color name="system_palette_key_color_primary_dark">#6076AC</color>
     <color name="system_palette_key_color_secondary_dark">#70778B</color>
     <color name="system_palette_key_color_tertiary_dark">#8C6D8C</color>
-    <color name="system_palette_key_color_neutral_dark">#76777D</color>
-    <color name="system_palette_key_color_neutral_variant_dark">#757780</color>
-    <color name="system_primary_fixed">#D9E2FF</color>
-    <color name="system_primary_fixed_dim">#B0C6FF</color>
+    <color name="system_primary_dark">#B0C6FF</color>
+    <color name="system_primary_container_dark">#2F4578</color>
+    <color name="system_scrim_dark">#000000</color>
+    <color name="system_secondary_dark">#C0C6DC</color>
+    <color name="system_secondary_container_dark">#404659</color>
+    <color name="system_shadow_dark">#000000</color>
+    <color name="system_surface_dark">#121318</color>
+    <color name="system_surface_bright_dark">#38393F</color>
+    <color name="system_surface_container_dark">#1E1F25</color>
+    <color name="system_surface_container_high_dark">#282A2F</color>
+    <color name="system_surface_container_highest_dark">#33343A</color>
+    <color name="system_surface_container_low_dark">#1A1B20</color>
+    <color name="system_surface_container_lowest_dark">#0C0E13</color>
+    <color name="system_surface_dim_dark">#121318</color>
+    <color name="system_surface_tint_dark">#B0C6FF</color>
+    <color name="system_surface_variant_dark">#44464F</color>
+    <color name="system_tertiary_dark">#E0BBDD</color>
+    <color name="system_tertiary_container_dark">#593D59</color>
+    <color name="system_text_hint_inverse_dark">#1A1B20</color>
+    <color name="system_text_primary_inverse_dark">#1A1B20</color>
+    <color name="system_text_primary_inverse_disable_only_dark">#1A1B20</color>
+    <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color>
+    <color name="system_text_secondary_and_tertiary_inverse_disabled_dark">#1A1B20</color>
     <color name="system_on_primary_fixed">#001945</color>
     <color name="system_on_primary_fixed_variant">#2F4578</color>
-    <color name="system_secondary_fixed">#DCE2F9</color>
-    <color name="system_secondary_fixed_dim">#C0C6DC</color>
     <color name="system_on_secondary_fixed">#151B2C</color>
     <color name="system_on_secondary_fixed_variant">#404659</color>
-    <color name="system_tertiary_fixed">#FDD7FA</color>
-    <color name="system_tertiary_fixed_dim">#E0BBDD</color>
     <color name="system_on_tertiary_fixed">#2A122C</color>
     <color name="system_on_tertiary_fixed_variant">#593D59</color>
-
-    <!--Colors used in Android system, from design system. These values can be overlaid at runtime
-     by OverlayManager RROs.-->
-    <color name="system_widget_background_light">#EEF0FF</color>
-    <color name="system_clock_hour_light">#373D50</color>
-    <color name="system_clock_minute_light">#3D5487</color>
-    <color name="system_clock_second_light">#4F659A</color>
-    <color name="system_theme_app_light">#D9E2FF</color>
-    <color name="system_on_theme_app_light">#475D92</color>
-    <color name="system_theme_app_ring_light">#94AAE4</color>
-    <color name="system_theme_notif_light">#E0BBDD</color>
+    <color name="system_primary_fixed">#D9E2FF</color>
+    <color name="system_primary_fixed_dim">#B0C6FF</color>
+    <color name="system_secondary_fixed">#DCE2F9</color>
+    <color name="system_secondary_fixed_dim">#C0C6DC</color>
+    <color name="system_tertiary_fixed">#FDD7FA</color>
+    <color name="system_tertiary_fixed_dim">#E0BBDD</color>
     <color name="system_brand_a_light">#475D92</color>
     <color name="system_brand_b_light">#6E7488</color>
     <color name="system_brand_c_light">#5E73A9</color>
     <color name="system_brand_d_light">#8A6A89</color>
-    <color name="system_under_surface_light">#000000</color>
-<color name="system_shade_active_light">#D9E2FF</color>
+    <color name="system_clock_hour_light">#373D50</color>
+    <color name="system_clock_minute_light">#3D5487</color>
+    <color name="system_clock_second_light">#725572</color>
     <color name="system_on_shade_active_light">#152E60</color>
     <color name="system_on_shade_active_variant_light">#2F4578</color>
-    <color name="system_shade_inactive_light">#2F3036</color>
     <color name="system_on_shade_inactive_light">#E1E2EC</color>
     <color name="system_on_shade_inactive_variant_light">#C5C6D0</color>
-    <color name="system_shade_disabled_light">#0C0E13</color>
+    <color name="system_on_theme_app_light">#475D92</color>
     <color name="system_overview_background_light">#C5C6D0</color>
-    <color name="system_widget_background_dark">#152E60</color>
-    <color name="system_clock_hour_dark">#8A90A5</color>
-    <color name="system_clock_minute_dark">#D9E2FF</color>
-    <color name="system_clock_second_dark">#B0C6FF</color>
-    <color name="system_theme_app_dark">#2F4578</color>
-    <color name="system_on_theme_app_dark">#B0C6FF</color>
-    <color name="system_theme_app_ring_dark">#94AAE4</color>
-    <color name="system_theme_notif_dark">#FDD7FA</color>
+    <color name="system_shade_active_light">#D9E2FF</color>
+    <color name="system_shade_disabled_light">#0C0E13</color>
+    <color name="system_shade_inactive_light">#2F3036</color>
+    <color name="system_theme_app_light">#D9E2FF</color>
+    <color name="system_theme_app_ring_light">#94AAE4</color>
+    <color name="system_theme_notif_light">#E0BBDD</color>
+    <color name="system_under_surface_light">#000000</color>
+    <color name="system_weather_temp_light">#4F659A</color>
+    <color name="system_widget_background_light">#EEF0FF</color>
     <color name="system_brand_a_dark">#B0C6FF</color>
     <color name="system_brand_b_dark">#DCE2F9</color>
     <color name="system_brand_c_dark">#7A90C8</color>
     <color name="system_brand_d_dark">#FDD7FA</color>
-    <color name="system_under_surface_dark">#000000</color>
-<color name="system_shade_active_dark">#D9E2FF</color>
+    <color name="system_clock_hour_dark">#8A90A5</color>
+    <color name="system_clock_minute_dark">#D9E2FF</color>
+    <color name="system_clock_second_dark">#FDD7FA</color>
     <color name="system_on_shade_active_dark">#001945</color>
     <color name="system_on_shade_active_variant_dark">#2F4578</color>
-    <color name="system_shade_inactive_dark">#2F3036</color>
     <color name="system_on_shade_inactive_dark">#E1E2EC</color>
     <color name="system_on_shade_inactive_variant_dark">#C5C6D0</color>
-    <color name="system_shade_disabled_dark">#0C0E13</color>
+    <color name="system_on_theme_app_dark">#B0C6FF</color>
     <color name="system_overview_background_dark">#50525A</color>
+    <color name="system_shade_active_dark">#D9E2FF</color>
+    <color name="system_shade_disabled_dark">#0C0E13</color>
+    <color name="system_shade_inactive_dark">#2F3036</color>
+    <color name="system_theme_app_dark">#2F4578</color>
+    <color name="system_theme_app_ring_dark">#94AAE4</color>
+    <color name="system_theme_notif_dark">#FDD7FA</color>
+    <color name="system_under_surface_dark">#000000</color>
+    <color name="system_weather_temp_dark">#B0C6FF</color>
+    <color name="system_widget_background_dark">#152E60</color>
 
     <!-- Accessibility shortcut icon background color -->
     <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
diff --git a/core/res/res/values/colors_dynamic.xml b/core/res/res/values/colors_dynamic.xml
new file mode 100644
index 0000000..ab283eb
--- /dev/null
+++ b/core/res/res/values/colors_dynamic.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Colors specific to Material themes. -->
+<resources>
+    <color name="materialColorBackground">@color/system_background_light</color>
+    <color name="materialColorControlActivated">@color/system_control_activated_light</color>
+    <color name="materialColorControlHighlight">@color/system_control_highlight_light</color>
+    <color name="materialColorControlNormal">@color/system_control_normal_light</color>
+    <color name="materialColorError">@color/system_error_light</color>
+    <color name="materialColorErrorContainer">@color/system_error_container_light</color>
+    <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</color>
+    <color name="materialColorInversePrimary">@color/system_inverse_primary_light</color>
+    <color name="materialColorInverseSurface">@color/system_inverse_surface_light</color>
+    <color name="materialColorOnBackground">@color/system_on_background_light</color>
+    <color name="materialColorOnError">@color/system_on_error_light</color>
+    <color name="materialColorOnErrorContainer">@color/system_on_error_container_light</color>
+    <color name="materialColorOnPrimary">@color/system_on_primary_light</color>
+    <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</color>
+    <color name="materialColorOnSecondary">@color/system_on_secondary_light</color>
+    <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</color>
+    <color name="materialColorOnSurface">@color/system_on_surface_light</color>
+    <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</color>
+    <color name="materialColorOnTertiary">@color/system_on_tertiary_light</color>
+    <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</color>
+    <color name="materialColorOutline">@color/system_outline_light</color>
+    <color name="materialColorOutlineVariant">@color/system_outline_variant_light</color>
+    <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</color>
+    <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</color>
+    <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</color>
+    <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</color>
+    <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</color>
+    <color name="materialColorPrimary">@color/system_primary_light</color>
+    <color name="materialColorPrimaryContainer">@color/system_primary_container_light</color>
+    <color name="materialColorScrim">@color/system_scrim_light</color>
+    <color name="materialColorSecondary">@color/system_secondary_light</color>
+    <color name="materialColorSecondaryContainer">@color/system_secondary_container_light</color>
+    <color name="materialColorShadow">@color/system_shadow_light</color>
+    <color name="materialColorSurface">@color/system_surface_light</color>
+    <color name="materialColorSurfaceBright">@color/system_surface_bright_light</color>
+    <color name="materialColorSurfaceContainer">@color/system_surface_container_light</color>
+    <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</color>
+    <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</color>
+    <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</color>
+    <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</color>
+    <color name="materialColorSurfaceDim">@color/system_surface_dim_light</color>
+    <color name="materialColorSurfaceTint">@color/system_surface_tint_light</color>
+    <color name="materialColorSurfaceVariant">@color/system_surface_variant_light</color>
+    <color name="materialColorTertiary">@color/system_tertiary_light</color>
+    <color name="materialColorTertiaryContainer">@color/system_tertiary_container_light</color>
+    <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</color>
+    <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</color>
+    <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</color>
+    <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</color>
+    <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</color>
+    <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+    <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+    <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+    <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+    <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+    <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+    <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+    <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+    <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+    <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+    <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+    <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+    <color name="customColorBrandA">@color/system_brand_a_light</color>
+    <color name="customColorBrandB">@color/system_brand_b_light</color>
+    <color name="customColorBrandC">@color/system_brand_c_light</color>
+    <color name="customColorBrandD">@color/system_brand_d_light</color>
+    <color name="customColorClockHour">@color/system_clock_hour_light</color>
+    <color name="customColorClockMinute">@color/system_clock_minute_light</color>
+    <color name="customColorClockSecond">@color/system_clock_second_light</color>
+    <color name="customColorOnShadeActive">@color/system_on_shade_active_light</color>
+    <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</color>
+    <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</color>
+    <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</color>
+    <color name="customColorOnThemeApp">@color/system_on_theme_app_light</color>
+    <color name="customColorOverviewBackground">@color/system_overview_background_light</color>
+    <color name="customColorShadeActive">@color/system_shade_active_light</color>
+    <color name="customColorShadeDisabled">@color/system_shade_disabled_light</color>
+    <color name="customColorShadeInactive">@color/system_shade_inactive_light</color>
+    <color name="customColorThemeApp">@color/system_theme_app_light</color>
+    <color name="customColorThemeAppRing">@color/system_theme_app_ring_light</color>
+    <color name="customColorThemeNotif">@color/system_theme_notif_light</color>
+    <color name="customColorUnderSurface">@color/system_under_surface_light</color>
+    <color name="customColorWeatherTemp">@color/system_weather_temp_light</color>
+    <color name="customColorWidgetBackground">@color/system_widget_background_light</color>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dc054a4..3f4ea2d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1849,6 +1849,10 @@
         <item>-1</item>
     </integer-array>
 
+     <!-- Specifies the delay in milliseconds after the last user input before turning off the
+          keyboard backlight.
+    -->
+    <integer name="config_keyboardBacklightTimeoutMs">30000</integer>
     <!-- An array describing the screen's backlight values corresponding to the brightness
          values in the config_screenBrightnessNits array.
 
@@ -4201,9 +4205,17 @@
          must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
     <string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
 
+    <!-- Allow the gesture to double tap the power button to trigger a target action. -->
+    <bool name="config_doubleTapPowerGestureEnabled">true</bool>
     <!-- Allow the gesture to double tap the power button twice to start the camera while the device
          is non-interactive. -->
     <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
+    <!-- Allow the gesture to double tap the power button twice to launch the wallet. -->
+    <bool name="config_walletDoubleTapPowerGestureEnabled">true</bool>
+    <!-- Default target action for double tap of the power button gesture.
+         0: Launch camera
+         1: Launch wallet -->
+    <integer name="config_defaultDoubleTapPowerGestureAction">0</integer>
 
     <!-- Allow the gesture to quick tap the power button multiple times to start the emergency sos
          experience while the device is non-interactive. -->
@@ -5894,6 +5906,11 @@
         <!-- <item>com.android.settings</item> -->
     </string-array>
 
+    <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner
+         SET_DEFAULT_ACCOUNT_FOR_CONTACTS permissions. The digest should be computed over the DER
+         encoding of the trusted certificate using the SHA-256 digest algorithm. -->
+    <string-array name="config_setContactsDefaultAccountKnownSigners">
+    </string-array>
 
     <!-- Class name of the custom country detector to be used. -->
     <string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string>
@@ -6563,7 +6580,7 @@
     </string-array>
 
     <!-- the number of the max cached processes in the system. -->
-    <integer name="config_customizedMaxCachedProcesses">32</integer>
+    <integer name="config_customizedMaxCachedProcesses">1024</integer>
 
     <!-- Whether this device should support taking app snapshots on closure -->
     <bool name="config_disableTaskSnapshots">false</bool>
@@ -7208,9 +7225,12 @@
     <!-- Package for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] -->
     <string name="identity_check_settings_package_name">com\u002eandroid\u002esettings</string>
 
-    <!-- The name of the service for forensic backup transport. -->
-    <string name="config_forensicBackupTransport" translatable="false"></string>
+    <!-- The name of the service for forensic event transport. -->
+    <string name="config_forensicEventTransport" translatable="false"></string>
 
     <!-- Whether to enable fp unlock when screen turns off on udfps devices -->
     <bool name="config_screen_off_udfps_enabled">false</bool>
+
+    <!-- The name of the system package that will hold the dependency installer role. -->
+    <string name="config_systemDependencyInstaller" translatable="false" />
 </resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 31e9913..4ec27a3 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -318,6 +318,12 @@
     <bool name="config_oem_enabled_satellite_access_allow">true</bool>
     <java-symbol type="bool" name="config_oem_enabled_satellite_access_allow" />
 
+    <!-- Whether the satellite modem support concurrent TN scanning while device is in
+         NTN mode.
+         -->
+    <bool name="config_satellite_modem_support_concurrent_tn_scanning">true</bool>
+    <java-symbol type="bool" name="config_satellite_modem_support_concurrent_tn_scanning" />
+
     <!-- The time duration in seconds which is used to decide whether the Location returned from
          LocationManager#getLastKnownLocation is fresh.
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index db75206..3757487 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -247,9 +247,14 @@
     <!-- Default padding for dialogs. -->
     <dimen name="dialog_padding">16dp</dimen>
 
-    <!-- The margin on the start of the content view (accommodates the icon) -->
+    <!-- The margin on the start of the content view (accommodates the icon)
+     This represents 16dp for the left margin + 24dp for the icon + 12dp for the right margin -->
     <dimen name="notification_content_margin_start">52dp</dimen>
 
+    <!-- The margin on the start of the content view (accommodates the icon), 2025 redesign version
+     This represents 16dp for the left margin + 40dp for the icon + 16dp for the right margin -->
+    <dimen name="notification_2025_content_margin_start">72dp</dimen>
+
     <!-- The margin on the end of most content views (ignores the expander) -->
     <dimen name="notification_content_margin_end">16dp</dimen>
 
@@ -310,6 +315,9 @@
     <!-- height of the notification header -->
     <dimen name="notification_header_height">56dp</dimen>
 
+    <!-- height of the notification header (2025 redesign version) -->
+    <dimen name="notification_2025_header_height">72dp</dimen>
+
     <!-- The height of the background for a notification header on a group -->
     <dimen name="notification_header_background_height">49.5dp</dimen>
 
@@ -331,9 +339,17 @@
     <!-- size (width and height) of the circle around the icon in the notification header -->
     <dimen name="notification_icon_circle_size">24dp</dimen>
 
+    <!-- size (width and height) of the circular icon in the notification header
+         (2025 redesign version) -->
+    <dimen name="notification_2025_icon_circle_size">40dp</dimen>
+
     <!-- padding between the notification icon and the circle containing it -->
     <dimen name="notification_icon_circle_padding">4dp</dimen>
 
+    <!-- padding between the notification icon and the circle containing it
+         (2025 redesign version) -->
+    <dimen name="notification_2025_icon_circle_padding">8dp</dimen>
+
     <!-- start margin of the icon circle in the notification view -->
     <dimen name="notification_icon_circle_start">16dp</dimen>
 
@@ -803,6 +819,8 @@
     <dimen name="notification_right_icon_big_margin_top">16dp</dimen>
     <!-- The size of the left icon -->
     <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
+    <!-- The size of the left icon (2025 redesign version) -->
+    <dimen name="notification_2025_left_icon_size">@dimen/notification_2025_icon_circle_size</dimen>
     <!-- The left padding of the left icon -->
     <dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen>
     <!-- The alpha of a disabled notification button -->
@@ -820,13 +838,13 @@
     <!-- The gap between segments in the notification progress bar -->
     <dimen name="notification_progress_segSeg_gap">2dp</dimen>
     <!-- The gap between a segment and a point in the notification progress bar -->
-    <dimen name="notification_progress_segPoint_gap">8dp</dimen>
-    <!-- The dash gap of the notification progress bar segments -->
-    <dimen name="notification_progress_segments_dash_gap">8dp</dimen>
-    <!-- The dash width of the notification progress bar segments -->
-    <dimen name="notification_progress_segments_dash_width">3dp</dimen>
+    <dimen name="notification_progress_segPoint_gap">4dp</dimen>
     <!-- The height of the notification progress bar segments -->
     <dimen name="notification_progress_segments_height">6dp</dimen>
+    <!-- The height of the notification progress bar faded segments -->
+    <dimen name="notification_progress_segments_faded_height">2dp</dimen>
+    <!-- The corner radius of the notification progress bar segments -->
+    <dimen name="notification_progress_segments_corner_radius">16dp</dimen>
     <!-- The radius of the notification progress bar points -->
     <dimen name="notification_progress_points_radius">6dp</dimen>
     <!-- The corner radius of the notification progress bar points drawn as rects -->
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b6436d0..b0b87d1d 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -131,6 +131,8 @@
     <public name="alternateLauncherIcons"/>
     <!-- @FlaggedApi(android.content.pm.Flags.FLAG_CHANGE_LAUNCHER_BADGING) -->
     <public name="alternateLauncherLabels"/>
+    <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) -->
+    <public name="pageSizeCompat" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01b60000">
@@ -140,12 +142,39 @@
   </staging-public-group>
 
   <staging-public-group type="string" first-id="0x01b40000">
+    <!-- @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+         @hide @SystemApi -->
+    <public name="config_systemDependencyInstaller" />
   </staging-public-group>
 
   <staging-public-group type="dimen" first-id="0x01b30000">
   </staging-public-group>
 
   <staging-public-group type="color" first-id="0x01b20000">
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_on_surface_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_primary_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_surface_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_scrim_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_shadow_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_surface_tint_light"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_on_surface_dark"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_primary_dark"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_inverse_surface_dark"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_scrim_dark"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_shadow_dark"/>
+    <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)-->
+    <public name="system_surface_tint_dark"/>
   </staging-public-group>
 
   <staging-public-group type="array" first-id="0x01b10000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index badb986..a2a19a2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2098,6 +2098,7 @@
   <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
   <java-symbol type="integer" name="config_autoBrightnessInitialLightSensorRate"/>
   <java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>
+  <java-symbol type="integer" name="config_keyboardBacklightTimeoutMs" />
   <java-symbol type="integer" name="config_carDockKeepsScreenOn" />
   <java-symbol type="integer" name="config_criticalBatteryWarningLevel" />
   <java-symbol type="integer" name="config_datause_notification_type" />
@@ -2388,6 +2389,8 @@
   <java-symbol type="layout" name="notification_material_action" />
   <java-symbol type="layout" name="notification_material_action_list" />
   <java-symbol type="layout" name="notification_material_action_tombstone" />
+  <java-symbol type="layout" name="notification_2025_template_collapsed_base" />
+  <java-symbol type="layout" name="notification_2025_template_header" />
   <java-symbol type="layout" name="notification_template_material_base" />
   <java-symbol type="layout" name="notification_template_material_heads_up_base" />
   <java-symbol type="layout" name="notification_template_material_compact_heads_up_base" />
@@ -3139,9 +3142,12 @@
   <!-- Gesture -->
   <java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
   <java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
-  <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
   <java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
   <java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
+  <java-symbol type="bool" name="config_doubleTapPowerGestureEnabled" />
+  <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
+  <java-symbol type="bool" name="config_walletDoubleTapPowerGestureEnabled" />
+  <java-symbol type="integer" name="config_defaultDoubleTapPowerGestureAction" />
   <java-symbol type="bool" name="config_emergencyGestureEnabled" />
   <java-symbol type="bool" name="config_defaultEmergencyGestureEnabled" />
   <java-symbol type="bool" name="config_defaultEmergencyGestureSoundEnabled" />
@@ -3875,9 +3881,9 @@
   <java-symbol type="dimen" name="notification_progress_tracker_height" />
   <java-symbol type="dimen" name="notification_progress_segSeg_gap" />
   <java-symbol type="dimen" name="notification_progress_segPoint_gap" />
-  <java-symbol type="dimen" name="notification_progress_segments_dash_gap" />
-  <java-symbol type="dimen" name="notification_progress_segments_dash_width" />
   <java-symbol type="dimen" name="notification_progress_segments_height" />
+  <java-symbol type="dimen" name="notification_progress_segments_faded_height" />
+  <java-symbol type="dimen" name="notification_progress_segments_corner_radius" />
   <java-symbol type="dimen" name="notification_progress_points_radius" />
   <java-symbol type="dimen" name="notification_progress_points_corner_radius" />
   <java-symbol type="dimen" name="notification_progress_points_inset" />
@@ -5310,73 +5316,91 @@
   <java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" />
   <java-symbol type="integer" name="config_accumulatedBatteryUsageStatsSpanSize" />
 
-  <java-symbol name="materialColorOnSecondaryFixedVariant" type="attr"/>
-  <java-symbol name="materialColorOnTertiaryFixedVariant" type="attr"/>
-  <java-symbol name="materialColorSurfaceContainerLowest" type="attr"/>
-  <java-symbol name="materialColorOnPrimaryFixedVariant" type="attr"/>
-  <java-symbol name="materialColorOnSecondaryContainer" type="attr"/>
-  <java-symbol name="materialColorOnTertiaryContainer" type="attr"/>
-  <java-symbol name="materialColorSurfaceContainerLow" type="attr"/>
-  <java-symbol name="materialColorOnPrimaryContainer" type="attr"/>
-  <java-symbol name="materialColorSecondaryFixedDim" type="attr"/>
-  <java-symbol name="materialColorOnErrorContainer" type="attr"/>
-  <java-symbol name="materialColorOnSecondaryFixed" type="attr"/>
-  <java-symbol name="materialColorOnSurfaceInverse" type="attr"/>
-  <java-symbol name="materialColorTertiaryFixedDim" type="attr"/>
-  <java-symbol name="materialColorOnTertiaryFixed" type="attr"/>
-  <java-symbol name="materialColorPrimaryFixedDim" type="attr"/>
-  <java-symbol name="materialColorSecondaryContainer" type="attr"/>
-  <java-symbol name="materialColorErrorContainer" type="attr"/>
-  <java-symbol name="materialColorOnPrimaryFixed" type="attr"/>
-  <java-symbol name="materialColorPrimaryInverse" type="attr"/>
-  <java-symbol name="materialColorSecondaryFixed" type="attr"/>
-  <java-symbol name="materialColorSurfaceInverse" type="attr"/>
-  <java-symbol name="materialColorSurfaceVariant" type="attr"/>
-  <java-symbol name="materialColorTertiaryContainer" type="attr"/>
-  <java-symbol name="materialColorTertiaryFixed" type="attr"/>
-  <java-symbol name="materialColorPrimaryContainer" type="attr"/>
-  <java-symbol name="materialColorOnBackground" type="attr"/>
-  <java-symbol name="materialColorPrimaryFixed" type="attr"/>
-  <java-symbol name="materialColorOnSecondary" type="attr"/>
-  <java-symbol name="materialColorOnTertiary" type="attr"/>
-  <java-symbol name="materialColorSurfaceDim" type="attr"/>
-  <java-symbol name="materialColorSurfaceBright" type="attr"/>
-  <java-symbol name="materialColorOnError" type="attr"/>
-  <java-symbol name="materialColorSurface" type="attr"/>
-  <java-symbol name="materialColorSurfaceContainerHigh" type="attr"/>
-  <java-symbol name="materialColorSurfaceContainerHighest" type="attr"/>
-  <java-symbol name="materialColorOnSurfaceVariant" type="attr"/>
-  <java-symbol name="materialColorOutline" type="attr"/>
-  <java-symbol name="materialColorOutlineVariant" type="attr"/>
-  <java-symbol name="materialColorOnPrimary" type="attr"/>
-  <java-symbol name="materialColorOnSurface" type="attr"/>
-  <java-symbol name="materialColorSurfaceContainer" type="attr"/>
-  <java-symbol name="materialColorPrimary" type="attr"/>
-  <java-symbol name="materialColorSecondary" type="attr"/>
-  <java-symbol name="materialColorTertiary" type="attr"/>
-  <java-symbol name="materialColorError" type="attr"/>
-
-  <java-symbol name="customColorWidgetBackground" type="attr"/>
-  <java-symbol name="customColorClockHour" type="attr"/>
-  <java-symbol name="customColorClockMinute" type="attr"/>
-  <java-symbol name="customColorClockSecond" type="attr"/>
-  <java-symbol name="customColorThemeApp" type="attr"/>
-  <java-symbol name="customColorOnThemeApp" type="attr"/>
-  <java-symbol name="customColorThemeAppRing" type="attr"/>
-  <java-symbol name="customColorThemeNotif" type="attr"/>
-  <java-symbol name="customColorBrandA" type="attr"/>
-  <java-symbol name="customColorBrandB" type="attr"/>
-  <java-symbol name="customColorBrandC" type="attr"/>
-  <java-symbol name="customColorBrandD" type="attr"/>
-  <java-symbol name="customColorUnderSurface" type="attr"/>
-  <java-symbol name="customColorShadeActive" type="attr"/>
-  <java-symbol name="customColorOnShadeActive" type="attr"/>
-  <java-symbol name="customColorOnShadeActiveVariant" type="attr"/>
-  <java-symbol name="customColorShadeInactive" type="attr"/>
-  <java-symbol name="customColorOnShadeInactive" type="attr"/>
-  <java-symbol name="customColorOnShadeInactiveVariant" type="attr"/>
-  <java-symbol name="customColorShadeDisabled" type="attr"/>
-  <java-symbol name="customColorOverviewBackground" type="attr"/>
+  <!--Dynamic Tokens-->
+  <java-symbol type="attr" name="materialColorBackground"/>
+  <java-symbol type="attr" name="materialColorControlActivated"/>
+  <java-symbol type="attr" name="materialColorControlHighlight"/>
+  <java-symbol type="attr" name="materialColorControlNormal"/>
+  <java-symbol type="attr" name="materialColorError"/>
+  <java-symbol type="attr" name="materialColorErrorContainer"/>
+  <java-symbol type="attr" name="materialColorInverseOnSurface"/>
+  <java-symbol type="attr" name="materialColorInversePrimary"/>
+  <java-symbol type="attr" name="materialColorInverseSurface"/>
+  <java-symbol type="attr" name="materialColorOnBackground"/>
+  <java-symbol type="attr" name="materialColorOnError"/>
+  <java-symbol type="attr" name="materialColorOnErrorContainer"/>
+  <java-symbol type="attr" name="materialColorOnPrimary"/>
+  <java-symbol type="attr" name="materialColorOnPrimaryContainer"/>
+  <java-symbol type="attr" name="materialColorOnSecondary"/>
+  <java-symbol type="attr" name="materialColorOnSecondaryContainer"/>
+  <java-symbol type="attr" name="materialColorOnSurface"/>
+  <java-symbol type="attr" name="materialColorOnSurfaceVariant"/>
+  <java-symbol type="attr" name="materialColorOnTertiary"/>
+  <java-symbol type="attr" name="materialColorOnTertiaryContainer"/>
+  <java-symbol type="attr" name="materialColorOutline"/>
+  <java-symbol type="attr" name="materialColorOutlineVariant"/>
+  <java-symbol type="attr" name="materialColorPaletteKeyColorNeutral"/>
+  <java-symbol type="attr" name="materialColorPaletteKeyColorNeutralVariant"/>
+  <java-symbol type="attr" name="materialColorPaletteKeyColorPrimary"/>
+  <java-symbol type="attr" name="materialColorPaletteKeyColorSecondary"/>
+  <java-symbol type="attr" name="materialColorPaletteKeyColorTertiary"/>
+  <java-symbol type="attr" name="materialColorPrimary"/>
+  <java-symbol type="attr" name="materialColorPrimaryContainer"/>
+  <java-symbol type="attr" name="materialColorScrim"/>
+  <java-symbol type="attr" name="materialColorSecondary"/>
+  <java-symbol type="attr" name="materialColorSecondaryContainer"/>
+  <java-symbol type="attr" name="materialColorShadow"/>
+  <java-symbol type="attr" name="materialColorSurface"/>
+  <java-symbol type="attr" name="materialColorSurfaceBright"/>
+  <java-symbol type="attr" name="materialColorSurfaceContainer"/>
+  <java-symbol type="attr" name="materialColorSurfaceContainerHigh"/>
+  <java-symbol type="attr" name="materialColorSurfaceContainerHighest"/>
+  <java-symbol type="attr" name="materialColorSurfaceContainerLow"/>
+  <java-symbol type="attr" name="materialColorSurfaceContainerLowest"/>
+  <java-symbol type="attr" name="materialColorSurfaceDim"/>
+  <java-symbol type="attr" name="materialColorSurfaceTint"/>
+  <java-symbol type="attr" name="materialColorSurfaceVariant"/>
+  <java-symbol type="attr" name="materialColorTertiary"/>
+  <java-symbol type="attr" name="materialColorTertiaryContainer"/>
+  <java-symbol type="attr" name="materialColorTextHintInverse"/>
+  <java-symbol type="attr" name="materialColorTextPrimaryInverse"/>
+  <java-symbol type="attr" name="materialColorTextPrimaryInverseDisableOnly"/>
+  <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverse"/>
+  <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverseDisabled"/>
+  <java-symbol type="attr" name="materialColorOnPrimaryFixed"/>
+  <java-symbol type="attr" name="materialColorOnPrimaryFixedVariant"/>
+  <java-symbol type="attr" name="materialColorOnSecondaryFixed"/>
+  <java-symbol type="attr" name="materialColorOnSecondaryFixedVariant"/>
+  <java-symbol type="attr" name="materialColorOnTertiaryFixed"/>
+  <java-symbol type="attr" name="materialColorOnTertiaryFixedVariant"/>
+  <java-symbol type="attr" name="materialColorPrimaryFixed"/>
+  <java-symbol type="attr" name="materialColorPrimaryFixedDim"/>
+  <java-symbol type="attr" name="materialColorSecondaryFixed"/>
+  <java-symbol type="attr" name="materialColorSecondaryFixedDim"/>
+  <java-symbol type="attr" name="materialColorTertiaryFixed"/>
+  <java-symbol type="attr" name="materialColorTertiaryFixedDim"/>
+  <java-symbol type="attr" name="customColorBrandA"/>
+  <java-symbol type="attr" name="customColorBrandB"/>
+  <java-symbol type="attr" name="customColorBrandC"/>
+  <java-symbol type="attr" name="customColorBrandD"/>
+  <java-symbol type="attr" name="customColorClockHour"/>
+  <java-symbol type="attr" name="customColorClockMinute"/>
+  <java-symbol type="attr" name="customColorClockSecond"/>
+  <java-symbol type="attr" name="customColorOnShadeActive"/>
+  <java-symbol type="attr" name="customColorOnShadeActiveVariant"/>
+  <java-symbol type="attr" name="customColorOnShadeInactive"/>
+  <java-symbol type="attr" name="customColorOnShadeInactiveVariant"/>
+  <java-symbol type="attr" name="customColorOnThemeApp"/>
+  <java-symbol type="attr" name="customColorOverviewBackground"/>
+  <java-symbol type="attr" name="customColorShadeActive"/>
+  <java-symbol type="attr" name="customColorShadeDisabled"/>
+  <java-symbol type="attr" name="customColorShadeInactive"/>
+  <java-symbol type="attr" name="customColorThemeApp"/>
+  <java-symbol type="attr" name="customColorThemeAppRing"/>
+  <java-symbol type="attr" name="customColorThemeNotif"/>
+  <java-symbol type="attr" name="customColorUnderSurface"/>
+  <java-symbol type="attr" name="customColorWeatherTemp"/>
+  <java-symbol type="attr" name="customColorWidgetBackground"/>
 
   <java-symbol name="system_widget_background_light" type="color"/>
   <java-symbol name="system_clock_hour_light" type="color"/>
@@ -5678,8 +5702,8 @@
   <java-symbol type="string" name="identity_check_settings_action" />
   <java-symbol type="string" name="identity_check_settings_package_name" />
 
-  <!-- Forensic backup transport -->
-  <java-symbol type="string" name="config_forensicBackupTransport" />
+  <!-- Forensic event transport -->
+  <java-symbol type="string" name="config_forensicEventTransport" />
 
   <!-- Fingerprint screen off unlock config -->
   <java-symbol type="bool" name="config_screen_off_udfps_enabled" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 352c390..d8346d8 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -239,73 +239,90 @@
         <item name="colorForeground">@color/foreground_device_default_dark</item>
         <item name="colorForegroundInverse">@color/foreground_device_default_light</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -357,73 +374,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
@@ -474,73 +508,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -593,73 +644,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -711,73 +779,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -837,73 +922,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -954,73 +1056,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -1070,73 +1189,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -1187,73 +1323,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -1320,73 +1473,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -1438,73 +1608,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -1554,73 +1741,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -1672,73 +1876,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1789,73 +2010,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1906,73 +2144,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -2023,73 +2278,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -2140,73 +2412,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -2257,73 +2546,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Theme for the dialog shown when an app crashes or ANRs. -->
@@ -2379,73 +2685,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -2494,73 +2817,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -2747,73 +3087,90 @@
         <item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
         <item name="panelColorBackground">?attr/colorBackgroundFloating</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -2864,73 +3221,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -2980,73 +3354,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -3097,73 +3488,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -3216,73 +3624,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -3334,73 +3759,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -3458,73 +3900,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
@@ -3578,73 +4037,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -3697,73 +4173,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -3817,73 +4310,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -3918,73 +4428,90 @@
         <item name="colorForeground">@color/foreground_device_default_light</item>
         <item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -4019,73 +4546,90 @@
         <item name="colorForeground">@color/foreground_device_default_light</item>
         <item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
@@ -4139,73 +4683,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -4260,73 +4821,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -4379,73 +4957,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -4497,73 +5092,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -4614,73 +5226,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -4731,73 +5360,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -4846,73 +5492,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
@@ -4968,74 +5631,90 @@
         <item name="colorListDivider">@color/list_divider_color_light</item>
         <item name="opacityListDivider">@color/list_divider_opacity_device_default_light</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light">
@@ -5072,74 +5751,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -5168,74 +5863,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -5286,73 +5997,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog">
@@ -5387,73 +6115,90 @@
         <!-- Dialog attributes -->
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase">
@@ -5528,73 +6273,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -5647,73 +6409,90 @@
         <!-- Toolbar attributes -->
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -5792,73 +6571,90 @@
         <item name="colorAccentSecondary">@color/system_secondary_dark</item>
         <item name="colorAccentTertiary">@color/system_tertiary_dark</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <style name="ThemeOverlay.DeviceDefault.Accent.Light">
@@ -5867,73 +6663,90 @@
         <item name="colorAccentSecondary">@color/system_secondary_dark</item>
         <item name="colorAccentTertiary">@color/system_tertiary_dark</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
@@ -5946,73 +6759,90 @@
         <item name="colorAccentSecondary">@color/system_secondary_dark</item>
         <item name="colorAccentTertiary">@color/system_tertiary_dark</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen">
@@ -6021,73 +6851,90 @@
         <item name="layout_gravity">center</item>
         <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorBackground">@color/system_background_light</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_light</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_light</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_light</item>
+        <item name="materialColorError">@color/system_error_light</item>
         <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item>
         <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
         <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
         <item name="materialColorOutline">@color/system_outline_light</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item>
         <item name="materialColorPrimary">@color/system_primary_light</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+        <item name="materialColorScrim">@color/system_scrim_light</item>
         <item name="materialColorSecondary">@color/system_secondary_light</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+        <item name="materialColorShadow">@color/system_shadow_light</item>
+        <item name="materialColorSurface">@color/system_surface_light</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
         <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
-        <item name="customColorClockHour">@color/system_clock_hour_light</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
-        <item name="customColorClockSecond">@color/system_clock_second_light</item>
-        <item name="customColorThemeApp">@color/system_theme_app_light</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_light</item>
         <item name="customColorBrandB">@color/system_brand_b_light</item>
         <item name="customColorBrandC">@color/system_brand_c_light</item>
         <item name="customColorBrandD">@color/system_brand_d_light</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
-        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorClockHour">@color/system_clock_hour_light</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_light</item>
+        <item name="customColorClockSecond">@color/system_clock_second_light</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_light</item>
+        <item name="customColorShadeActive">@color/system_shade_active_light</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_light</item>
+        <item name="customColorThemeApp">@color/system_theme_app_light</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_light</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_light</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_light</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
@@ -6107,73 +6954,90 @@
         <item name="textColorPrimary">@color/system_neutral1_900</item>
         <item name="textColorSecondary">@color/system_neutral2_700</item>
 
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorBackground">@color/system_background_dark</item>
+        <item name="materialColorControlActivated">@color/system_control_activated_dark</item>
+        <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item>
+        <item name="materialColorControlNormal">@color/system_control_normal_dark</item>
+        <item name="materialColorError">@color/system_error_dark</item>
         <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item>
+        <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item>
+        <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item>
         <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
         <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
+        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
+        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
+        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
         <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
+        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
+        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
         <item name="materialColorOutline">@color/system_outline_dark</item>
         <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item>
+        <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item>
+        <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item>
+        <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item>
+        <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item>
         <item name="materialColorPrimary">@color/system_primary_dark</item>
+        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
+        <item name="materialColorScrim">@color/system_scrim_dark</item>
         <item name="materialColorSecondary">@color/system_secondary_dark</item>
+        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
+        <item name="materialColorShadow">@color/system_shadow_dark</item>
+        <item name="materialColorSurface">@color/system_surface_dark</item>
+        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
+        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
+        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
+        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
+        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
+        <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item>
+        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
         <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
-
-        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
-        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
-        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
-        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
-        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
-        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
-        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
-        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+        <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item>
+        <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item>
+        <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item>
+        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
+        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
+        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
+        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
+        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
+        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
+        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
+        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
+        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
+        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
+        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
+        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
         <item name="customColorBrandA">@color/system_brand_a_dark</item>
         <item name="customColorBrandB">@color/system_brand_b_dark</item>
         <item name="customColorBrandC">@color/system_brand_c_dark</item>
         <item name="customColorBrandD">@color/system_brand_d_dark</item>
-        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
-        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorClockHour">@color/system_clock_hour_dark</item>
+        <item name="customColorClockMinute">@color/system_clock_minute_dark</item>
+        <item name="customColorClockSecond">@color/system_clock_second_dark</item>
         <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item>
         <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item>
-        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
         <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item>
         <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item>
-        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item>
         <item name="customColorOverviewBackground">@color/system_overview_background_dark</item>
+        <item name="customColorShadeActive">@color/system_shade_active_dark</item>
+        <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item>
+        <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item>
+        <item name="customColorThemeApp">@color/system_theme_app_dark</item>
+        <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item>
+        <item name="customColorThemeNotif">@color/system_theme_notif_dark</item>
+        <item name="customColorUnderSurface">@color/system_under_surface_dark</item>
+        <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item>
+        <item name="customColorWidgetBackground">@color/system_widget_background_dark</item>
     </style>
     <style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight">
         <item name="colorListDivider">@color/list_divider_opacity_device_default_light</item>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
index 22d0226..e735784 100644
--- a/core/res/res/xml/bookmarks.xml
+++ b/core/res/res/xml/bookmarks.xml
@@ -31,29 +31,37 @@
        'u': Calculator
        'y': YouTube
 -->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <bookmark
         role="android.app.role.BROWSER"
-        shortcut="b" />
+        androidprv:keycode="KEYCODE_B"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CONTACTS"
-        shortcut="c" />
+        androidprv:keycode="KEYCODE_C"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_EMAIL"
-        shortcut="e" />
+        androidprv:keycode="KEYCODE_E"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALENDAR"
-        shortcut="k" />
+        androidprv:keycode="KEYCODE_K"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MAPS"
-        shortcut="m" />
+        androidprv:keycode="KEYCODE_M"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MUSIC"
-        shortcut="p" />
+        androidprv:keycode="KEYCODE_P"
+        androidprv:modifierState="META" />
     <bookmark
         role="android.app.role.SMS"
-        shortcut="s" />
+        androidprv:keycode="KEYCODE_S"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALCULATOR"
-        shortcut="u" />
+        androidprv:keycode="KEYCODE_U"
+        androidprv:modifierState="META" />
 </bookmarks>
diff --git a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
index 1721e1e..f62d420 100644
--- a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java
@@ -79,7 +79,7 @@
         TEST_EDITOR_INFO.label = "testLabel";
         TEST_EDITOR_INFO.packageName = "android.view.inputmethod";
         TEST_EDITOR_INFO.fieldId = 0;
-        TEST_EDITOR_INFO.autofillId = AutofillId.NO_AUTOFILL_ID;
+        TEST_EDITOR_INFO.setAutofillId(AutofillId.NO_AUTOFILL_ID);
         TEST_EDITOR_INFO.fieldName = "testField";
         TEST_EDITOR_INFO.extras = new Bundle();
         TEST_EDITOR_INFO.extras.putString("testKey", "testValue");
@@ -507,7 +507,8 @@
                 + "prefix: supportedHandwritingGestureTypes=(none)\n"
                 + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n"
                 + "prefix: isStylusHandwritingEnabled=false\n"
-                + "prefix: contentMimeTypes=null\n");
+                + "prefix: contentMimeTypes=null\n"
+                + "prefix: writingToolsEnabled=true\n");
     }
 
     @Test
@@ -531,7 +532,7 @@
             info.setStylusHandwritingEnabled(true);
         }
         info.packageName = "android.view.inputmethod";
-        info.autofillId = new AutofillId(123);
+        info.setAutofillId(new AutofillId(123));
         info.fieldId = 456;
         info.fieldName = "testField";
         info.extras = new Bundle();
@@ -539,6 +540,7 @@
         info.hintLocales = LocaleList.forLanguageTags("en,es,zh");
         info.contentMimeTypes = new String[] {"image/png"};
         info.targetInputMethodUser = UserHandle.of(10);
+        info.setWritingToolsEnabled(false);
         final StringBuilder sb = new StringBuilder();
         info.dump(new StringBuilderPrinter(sb), "prefix2: ");
         assertThat(sb.toString()).isEqualTo(
@@ -555,7 +557,8 @@
                         + "prefix2: supportedHandwritingGesturePreviewTypes=SELECT\n"
                         + "prefix2: isStylusHandwritingEnabled=" + isStylusHandwritingEnabled + "\n"
                         + "prefix2: contentMimeTypes=[image/png]\n"
-                        + "prefix2: targetInputMethodUserId=10\n");
+                        + "prefix2: targetInputMethodUserId=10\n"
+                        + "prefix2: writingToolsEnabled=false\n");
     }
 
     @Test
@@ -576,7 +579,8 @@
                         + "prefix: supportedHandwritingGestureTypes=(none)\n"
                         + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n"
                         + "prefix: isStylusHandwritingEnabled=false\n"
-                        + "prefix: contentMimeTypes=null\n");
+                        + "prefix: contentMimeTypes=null\n"
+                        + "prefix: writingToolsEnabled=true\n");
     }
 
     @Test
@@ -597,7 +601,7 @@
     @Test
     public void testKindofEqualsComparesAutofillId() {
         final EditorInfo infoCopy = TEST_EDITOR_INFO.createCopyInternal();
-        infoCopy.autofillId = new AutofillId(42);
+        infoCopy.setAutofillId(new AutofillId(42));
         assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy));
     }
 
@@ -621,4 +625,9 @@
         infoCopy.extras.putString("testKey2", "testValue");
         assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy));
     }
+
+    @Test
+    public void testWritingToolsEnabledbyDefault() {
+        assertTrue(TEST_EDITOR_INFO.isWritingToolsEnabled());
+    }
 }
diff --git a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
index 232abe2..7f069ad 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java
@@ -22,7 +22,7 @@
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
 
-public class ActivityTestsBase extends AndroidTestCase 
+public class ActivityTestsBase extends AndroidTestCase
         implements PerformanceTestCase, LaunchpadActivity.CallingTest {
     public static final String PERMISSION_GRANTED =
             "com.android.frameworks.coretests.permission.TEST_GRANTED";
@@ -111,7 +111,6 @@
 
     public void finishWithResult(int resultCode, Intent data) {
         RuntimeException where = new RuntimeException("Original error was here");
-        where.fillInStackTrace();
         finishWithResult(resultCode, data, where);
     }
 
@@ -194,15 +193,15 @@
     public int getResultCode() {
         return mResultCode;
     }
-    
+
     public Intent getResultData() {
         return mData;
     }
-    
+
     public RuntimeException getResultStack() {
         return mResultStack;
     }
-    
+
     public void onTimeout() {
         String msg = mExpecting == null
                 ? "Timeout" : ("Timeout while expecting " + mExpecting);
diff --git a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
index fda249f..9b358e0 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java
@@ -461,7 +461,6 @@
         mResultCode = resultCode;
         mData = data;
         mResultStack = new RuntimeException("Original error was here");
-        mResultStack.fillInStackTrace();
     }
 
     private void registerMyReceiver(IntentFilter filter) {
diff --git a/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java
new file mode 100644
index 0000000..df5cd4e
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@Presubmit
+@RunWith(JUnit4.class)
+public final class SharedLibraryInfoTest {
+
+    @Rule
+    public final CheckFlagsRule checkFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private static final String LIBRARY_NAME = "name";
+    private static final long VERSION_MAJOR = 1L;
+    private static final List<String> CERT_DIGESTS = ImmutableList.of("digest1", "digest2");
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
+    public void sharedLibraryInfo_serializedAndDeserialized_retainsCertDigestInfo() {
+        SharedLibraryInfo toParcel = new SharedLibraryInfo(LIBRARY_NAME, VERSION_MAJOR,
+                SharedLibraryInfo.TYPE_SDK_PACKAGE, CERT_DIGESTS);
+
+        SharedLibraryInfo fromParcel = parcelAndUnparcel(toParcel);
+
+        assertThat(fromParcel.getCertDigests().size()).isEqualTo(toParcel.getCertDigests().size());
+        assertThat(fromParcel.getCertDigests().get(0)).isEqualTo(toParcel.getCertDigests().get(0));
+        assertThat(fromParcel.getCertDigests().get(1)).isEqualTo(toParcel.getCertDigests().get(1));
+    }
+
+    private SharedLibraryInfo parcelAndUnparcel(SharedLibraryInfo sharedLibraryInfo) {
+        Parcel parcel = Parcel.obtain();
+        parcel.setDataPosition(0);
+        sharedLibraryInfo.writeToParcel(parcel, /* flags= */0);
+
+        parcel.setDataPosition(0);
+        return SharedLibraryInfo.CREATOR.createFromParcel(parcel);
+    }
+}
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index 9552c88..6a5224d 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -16,6 +16,11 @@
 
 package android.hardware.display;
 
+import static android.hardware.display.DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED;
+import static android.hardware.display.DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
+import static android.hardware.display.DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE;
+
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -28,13 +33,19 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.view.DisplayInfo;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.display.feature.flags.Flags;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -55,6 +66,10 @@
 @RunWith(AndroidJUnit4.class)
 public class DisplayManagerGlobalTest {
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static final long ALL_DISPLAY_EVENTS =
             DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED
             | DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED
@@ -117,6 +132,33 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+    public void testDisplayListenerIsCalled_WhenDisplayPropertyChangeEventOccurs()
+            throws RemoteException {
+        mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+                INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE
+                        | INTERNAL_EVENT_FLAG_DISPLAY_STATE,
+                null);
+        Mockito.verify(mDisplayManager)
+                .registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
+        IDisplayManagerCallback callback = mCallbackCaptor.getValue();
+
+        int displayId = 1;
+
+        Mockito.reset(mListener);
+        callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED);
+        waitForHandler();
+        Mockito.verify(mListener).onDisplayChanged(eq(displayId));
+        Mockito.verifyNoMoreInteractions(mListener);
+
+        Mockito.reset(mListener);
+        callback.onDisplayEvent(displayId, EVENT_DISPLAY_STATE_CHANGED);
+        waitForHandler();
+        Mockito.verify(mListener).onDisplayChanged(eq(displayId));
+        Mockito.verifyNoMoreInteractions(mListener);
+    }
+
+    @Test
     public void testDisplayListenerIsNotCalled_WhenClientIsNotSubscribed() throws RemoteException {
         // First we subscribe to all events in order to test that the subsequent calls to
         // registerDisplayListener will update the event mask.
@@ -231,6 +273,53 @@
         verify(mListener2, never()).onDisplayChanged(anyInt());
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
+    public void testMapFlagsToInternalEventFlag() {
+        // Test public flags mapping
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_ADDED, 0));
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CHANGED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, 0));
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, 0));
+        assertEquals(INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(
+                                DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
+                                0));
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(
+                                DisplayManager.EVENT_FLAG_DISPLAY_STATE,
+                                0));
+
+        // test private flags mapping
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(0,
+                                DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED));
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(0,
+                                DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED));
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(0,
+                                DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+        // Test both public and private flags mapping
+        assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED
+                        | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
+                mDisplayManagerGlobal
+                        .mapFlagsToInternalEventFlag(
+                                DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
+                                DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+    }
+
     private void waitForHandler() {
         mHandler.runWithScissors(() -> {
         }, 0);
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
index a6de611..8969b2b 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
+++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
@@ -16,7 +16,10 @@
 
 package android.hardware.display
 
+import android.graphics.PointF
+import android.graphics.RectF
 import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM
+import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT
 import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP
 import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT
 import android.view.Display
@@ -469,4 +472,205 @@
         assertThat(actualDisplay4.offset).isEqualTo(-400f)
         assertThat(actualDisplay4.children).isEmpty()
     }
-}
\ No newline at end of file
+
+    @Test
+    fun rearrange_twoDisplays() {
+        val nodes = rearrangeRects(
+            // Arrange in staggered manner, connected vertically.
+            RectF(100f, 100f, 250f, 200f),
+            RectF(150f, 200f, 300f, 300f),
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1])
+        assertThat(nodes[1].children).isEmpty()
+        assertPositioning(nodes, Pair(POSITION_BOTTOM, 50f))
+    }
+
+    @Test
+    fun rearrange_reverseOrderOfSeveralDisplays() {
+        val nodes = rearrangeRects(
+            RectF(0f, 0f, 150f, 100f),
+            RectF(-150f, 0f, 0f, 100f),
+            RectF(-300f, 0f, -150f, 100f),
+            RectF(-450f, 0f, -300f, 100f),
+        )
+
+        assertPositioning(
+            nodes,
+            Pair(POSITION_LEFT, 0f),
+            Pair(POSITION_LEFT, 0f),
+            Pair(POSITION_LEFT, 0f),
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1])
+        assertThat(nodes[1].children).containsExactly(nodes[2])
+        assertThat(nodes[2].children).containsExactly(nodes[3])
+        assertThat(nodes[3].children).isEmpty()
+    }
+
+    @Test
+    fun rearrange_crossWithRootInCenter() {
+        val nodes = rearrangeRects(
+            RectF(0f, 0f, 150f, 100f),
+            RectF(-150f, 0f, 0f, 100f),
+            RectF(0f,-100f, 150f, 0f),
+            RectF(150f, 0f, 300f, 100f),
+            RectF(0f, 100f, 150f, 200f),
+        )
+
+        assertPositioning(
+            nodes,
+            Pair(POSITION_LEFT, 0f),
+            Pair(POSITION_TOP, 0f),
+            Pair(POSITION_RIGHT, 0f),
+            Pair(POSITION_BOTTOM, 0f),
+        )
+
+        assertThat(nodes[0].children)
+            .containsExactly(nodes[1], nodes[2], nodes[3], nodes[4])
+    }
+
+    @Test
+    fun rearrange_elbowArrangementDoesNotUseCornerAdjacency1() {
+        val nodes = rearrangeRects(
+            //     2
+            //     |
+            // 0 - 1
+
+            RectF(0f, 0f, 100f, 100f),
+            RectF(100f, 0f, 200f, 100f),
+            RectF(100f, -100f, 200f, 0f),
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1])
+        assertThat(nodes[1].children).containsExactly(nodes[2])
+        assertThat(nodes[2].children).isEmpty()
+
+        assertPositioning(
+            nodes,
+            Pair(POSITION_RIGHT, 0f),
+            Pair(POSITION_TOP, 0f),
+        )
+    }
+
+    @Test
+    fun rearrange_elbowArrangementDoesNotUseCornerAdjacency2() {
+        val nodes = rearrangeRects(
+            //     0
+            //     |
+            //     1
+            //     |
+            // 3 - 2
+
+            RectF(0f, 0f, 100f, 100f),
+            RectF(0f, 100f, 100f, 200f),
+            RectF(0f, 200f, 100f, 300f),
+            RectF(-100f, 200f, 0f, 300f),
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1])
+        assertThat(nodes[1].children).containsExactly(nodes[2])
+        assertThat(nodes[2].children).containsExactly(nodes[3])
+        assertThat(nodes[3].children).isEmpty()
+
+        assertPositioning(
+            nodes,
+            Pair(POSITION_BOTTOM, 0f),
+            Pair(POSITION_BOTTOM, 0f),
+            Pair(POSITION_LEFT, 0f),
+        )
+    }
+
+    @Test
+    fun rearrange_useLargerEdge() {
+        val nodes = rearrangeRects(
+            //444111
+            //444111
+            //444111
+            //  000222
+            //  000222
+            //  000222
+            //    333
+            //    333
+            //    333
+            RectF(20f, 30f, 50f, 60f),
+            RectF(30f, 0f, 60f, 30f),
+            RectF(50f, 30f, 80f, 60f),
+            RectF(40f, 60f, 70f, 90f),
+            RectF(0f, 0f, 30f, 30f),
+        )
+
+        assertPositioning(
+            nodes,
+            Pair(POSITION_TOP, 10f),
+            Pair(POSITION_RIGHT, 0f),
+            Pair(POSITION_BOTTOM, -10f),
+            Pair(POSITION_LEFT, 0f),
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1], nodes[2])
+        assertThat(nodes[1].children).containsExactly(nodes[4])
+        assertThat(nodes[2].children).containsExactly(nodes[3])
+        (3..4).forEach { assertThat(nodes[it].children).isEmpty() }
+    }
+
+    @Test
+    fun rearrange_closeGaps() {
+        val nodes = rearrangeRects(
+            //000
+            //000 111
+            //000 111
+            //    111
+            //
+            //        222
+            //        222
+            //        222
+            RectF(0f, 0f, 30f, 30f),
+            RectF(40f, 10f, 70f, 40f),
+            RectF(80.5f, 50f, 110f, 80f),  // left+=0.5 to cause a preference for TOP/BOTTOM attach
+        )
+
+        assertPositioning(
+            nodes,
+            // In the case of corner adjacency, we prefer a left/right attachment.
+            Pair(POSITION_RIGHT, 10f),
+            Pair(POSITION_BOTTOM, 40.5f),  // TODO: fix implementation to remove this gap
+        )
+
+        assertThat(nodes[0].children).containsExactly(nodes[1])
+        assertThat(nodes[1].children).containsExactly(nodes[2])
+        assertThat(nodes[2].children).isEmpty()
+    }
+
+    /**
+     * Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the
+     * root at index 0. The number of nodes is inferred from the number of positions passed.
+     */
+    private fun rearrangeRects(vararg pos : RectF) : List<DisplayTopology.TreeNode> {
+        // Generates a linear sequence of nodes in order in the List from root to leaf,
+        // left-to-right. IDs are ascending from 0 to count - 1.
+
+        val nodes = pos.indices.map {
+            DisplayTopology.TreeNode(it, pos[it].width(), pos[it].height(), POSITION_RIGHT, 0f)
+        }
+
+        nodes.forEachIndexed { id, node ->
+            if (id > 0) {
+                nodes[id - 1].addChild(node)
+            }
+        }
+
+        DisplayTopology(nodes[0], 0).rearrange(pos.indices.associateWith {
+            PointF(pos[it].left, pos[it].top)
+        })
+
+        return nodes
+    }
+
+    private fun assertPositioning(
+            nodes : List<DisplayTopology.TreeNode>, vararg positions : Pair<Int, Float>) {
+        assertThat(nodes.drop(1).map { Pair(it.position, it.offset )})
+            .containsExactly(*positions)
+            .inOrder()
+    }
+}
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 6149382..4620cb8 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -12,3 +12,6 @@
 
 # Caching
 per-file IpcDataCache* = file:/PERFORMANCE_OWNERS
+
+# RemoteCallbackList
+per-file RemoteCallbackListTest.java = shayba@google.com
diff --git a/core/tests/vibrator/src/android/os/VibrationEffectTest.java b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
index 1cd1190..ccc5108 100644
--- a/core/tests/vibrator/src/android/os/VibrationEffectTest.java
+++ b/core/tests/vibrator/src/android/os/VibrationEffectTest.java
@@ -414,10 +414,10 @@
 
     @Test
     @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
-    public void computeLegacyPattern_effectsViaStartWaveformEnvelope() {
-        // Effects created via startWaveformEnvelope are not expected to be converted to long[]
+    public void computeLegacyPattern_effectsViaWaveformEnvelopeBuilder() {
+        // Effects created via waveformEnvelopeBuilder are not expected to be converted to long[]
         // patterns, as they are not configured to always play with the default amplitude.
-        VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
+        VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
@@ -426,7 +426,8 @@
 
         assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
 
-        effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 60)
+        effect = new VibrationEffect.WaveformEnvelopeBuilder()
+                .setInitialFrequencyHz(/*initialFrequencyHz=*/ 60)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
@@ -644,7 +645,7 @@
     @Test
     @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testValidateWaveformEnvelopeBuilder() {
-        VibrationEffect.startWaveformEnvelope()
+        new VibrationEffect.WaveformEnvelopeBuilder()
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
@@ -652,7 +653,8 @@
                 .build()
                 .validate();
 
-        VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+        new VibrationEffect.WaveformEnvelopeBuilder()
+                .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80)
@@ -661,13 +663,13 @@
                 .validate();
 
         VibrationEffect.createRepeatingEffect(
-                /*preamble=*/ VibrationEffect.startWaveformEnvelope()
+                /*preamble=*/ new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f,
                                 /*timeMillis=*/ 50)
                         .build(),
-                /*repeatingEffect=*/ VibrationEffect.startWaveformEnvelope()
+                /*repeatingEffect=*/ new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
@@ -676,7 +678,7 @@
         ).validate();
 
         VibrationEffect.createRepeatingEffect(
-                /*effect=*/ VibrationEffect.startWaveformEnvelope()
+                /*effect=*/ new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f,
@@ -685,59 +687,70 @@
         ).validate();
 
         assertThrows(IllegalStateException.class,
-                () -> VibrationEffect.startWaveformEnvelope().build().validate());
+                () -> new VibrationEffect.WaveformEnvelopeBuilder().build().validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope()
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope()
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope()
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope()
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
                         .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
                                 /*timeMillis=*/ 0)
                         .build()
                         .validate());
 
         assertThrows(IllegalStateException.class,
-                () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                         .build().validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                         .addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                         .addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                         .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f,
                                 /*timeMillis=*/ 20)
                         .build()
                         .validate());
         assertThrows(IllegalArgumentException.class,
-                () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30)
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                         .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
                                 /*timeMillis=*/ 0)
                         .build()
                         .validate());
+        assertThrows(IllegalArgumentException.class,
+                () -> new VibrationEffect.WaveformEnvelopeBuilder()
+                        .setInitialFrequencyHz(/*initialFrequencyHz=*/ 0)
+                        .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f,
+                                /*timeMillis=*/ 20)
+                        .build().validate());
     }
 
     @Test
@@ -1381,14 +1394,15 @@
     @Test
     @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testIsHapticFeedbackCandidate_longEnvelopeEffects_notCandidates() {
-        assertFalse(VibrationEffect.startWaveformEnvelope()
+        assertFalse(new VibrationEffect.WaveformEnvelopeBuilder()
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
                 .build()
                 .isHapticFeedbackCandidate());
-        assertFalse(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 40)
+        assertFalse(new VibrationEffect.WaveformEnvelopeBuilder()
+                .setInitialFrequencyHz(/*initialFrequencyHz=*/ 40)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800)
@@ -1413,13 +1427,14 @@
     @Test
     @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testIsHapticFeedbackCandidate_shortEnvelopeEffects_areCandidates() {
-        assertTrue(VibrationEffect.startWaveformEnvelope()
+        assertTrue(new VibrationEffect.WaveformEnvelopeBuilder()
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
                 .build()
                 .isHapticFeedbackCandidate());
-        assertTrue(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+        assertTrue(new VibrationEffect.WaveformEnvelopeBuilder()
+                .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 541ca60..fea7cb4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -93,6 +93,10 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.media.quality">
+        <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.mtp">
         <permission name="android.permission.ACCESS_MTP"/>
         <permission name="android.permission.MANAGE_USB"/>
@@ -262,6 +266,8 @@
         <!-- BLUETOOTH_PRIVILEGED is needed for test only -->
         <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
         <permission name="android.permission.BIND_APPWIDGET"/>
+        <!-- Needed for CTS tests only -->
+        <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/>
         <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
@@ -597,6 +603,9 @@
         <!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest -->
         <permission name="android.permission.READ_SYSTEM_PREFERENCES" />
         <permission name="android.permission.WRITE_SYSTEM_PREFERENCES" />
+        <!-- Permission required for CTS test - ForensicManagerTest -->
+        <permission name="android.permission.READ_FORENSIC_STATE" />
+        <permission name="android.permission.MANAGE_FORENSIC_STATE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java
index 5c294aa..c6ae680 100644
--- a/graphics/java/android/graphics/BlendMode.java
+++ b/graphics/java/android/graphics/BlendMode.java
@@ -571,10 +571,10 @@
     }
 
     @NonNull
-    private final Xfermode mXfermode;
+    private final PorterDuffXfermode mXfermode;
 
     BlendMode(int mode) {
-        mXfermode = new Xfermode();
+        mXfermode = new PorterDuffXfermode();
         mXfermode.porterDuffMode = mode;
     }
 
@@ -582,7 +582,7 @@
      * @hide
      */
     @NonNull
-    public Xfermode getXfermode() {
+    public PorterDuffXfermode getXfermode() {
         return mXfermode;
     }
 }
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 977aeaa..e714568 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -40,9 +40,12 @@
      * @param mode     The mode that combines the colors from the two shaders. If mode
      *                 is null, then SRC_OVER is assumed.
      */
+    //TODO(358126864): allow a ComposeShader to accept a RuntimeXfermode
     @Deprecated
     public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) {
-        this(shaderA, shaderB, mode.porterDuffMode);
+        this(shaderA, shaderB,
+                mode instanceof PorterDuffXfermode ? ((PorterDuffXfermode) mode).porterDuffMode
+                : BlendMode.SRC_OVER.getXfermode().porterDuffMode);
     }
 
     /**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 56bb0f0..9bf4d65 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -71,6 +71,7 @@
     private long mNativePaint;
     private long mNativeShader;
     private long mNativeColorFilter;
+    private long mNativeXfermode;
 
     // Use a Holder to allow static initialization of Paint in the boot image.
     private static class NoImagePreloadHolder {
@@ -735,6 +736,7 @@
         mPathEffect = null;
         mShader = null;
         mNativeShader = 0;
+        mNativeXfermode = 0;
         mTypeface = null;
         mXfermode = null;
 
@@ -780,6 +782,7 @@
         mNativeShader = paint.mNativeShader;
         mTypeface = paint.mTypeface;
         mXfermode = paint.mXfermode;
+        mNativeXfermode = paint.mNativeXfermode;
 
         mHasCompatScaling = paint.mHasCompatScaling;
         mCompatScaling = paint.mCompatScaling;
@@ -815,7 +818,7 @@
      *
      * Note: Although this method is |synchronized|, this is simply so it
      * is not thread-hostile to multiple threads calling this method. It
-     * is still unsafe to attempt to change the Shader/ColorFilter while
+     * is still unsafe to attempt to change the Shader/ColorFilter/Xfermode while
      * another thread attempts to access the native object.
      *
      * @hide
@@ -833,6 +836,15 @@
             mNativeColorFilter = newNativeColorFilter;
             nSetColorFilter(mNativePaint, mNativeColorFilter);
         }
+        if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) {
+            if (mXfermode instanceof RuntimeXfermode) {
+                long newNativeXfermode = ((RuntimeXfermode) mXfermode).createNativeInstance();
+                if (newNativeXfermode != mNativeXfermode) {
+                    mNativeXfermode = newNativeXfermode;
+                    nSetXfermode(mNativePaint, mNativeXfermode);
+                }
+            }
+        }
         return mNativePaint;
     }
 
@@ -1427,16 +1439,17 @@
     }
 
     /**
-     * Get the paint's blend mode object.
+     * Get the paint's blend mode object. Will return null if there is a Xfermode applied that
+     * cannot be represented by a blend mode (i.e. a custom {@code RuntimeXfermode}
      *
      * @return the paint's blend mode (or null)
      */
     @Nullable
     public BlendMode getBlendMode() {
-        if (mXfermode == null) {
+        if (mXfermode == null || !(mXfermode instanceof PorterDuffXfermode)) {
             return null;
         } else {
-            return BlendMode.fromValue(mXfermode.porterDuffMode);
+            return BlendMode.fromValue(((PorterDuffXfermode) mXfermode).porterDuffMode);
         }
     }
 
@@ -1459,8 +1472,17 @@
 
     @Nullable
     private Xfermode installXfermode(Xfermode xfermode) {
-        int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
-        int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
+        if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) {
+            if (xfermode instanceof RuntimeXfermode) {
+                mXfermode = xfermode;
+                nSetXfermode(mNativePaint, ((RuntimeXfermode) xfermode).createNativeInstance());
+                return xfermode;
+            }
+        }
+        int newMode = (xfermode instanceof PorterDuffXfermode)
+                ? ((PorterDuffXfermode) xfermode).porterDuffMode : PorterDuffXfermode.DEFAULT;
+        int curMode = (mXfermode instanceof PorterDuffXfermode)
+                ? ((PorterDuffXfermode) mXfermode).porterDuffMode : PorterDuffXfermode.DEFAULT;
         if (newMode != curMode) {
             nSetXfermode(mNativePaint, newMode);
         }
@@ -3823,6 +3845,8 @@
     @CriticalNative
     private static native void nSetXfermode(long paintPtr, int xfermode);
     @CriticalNative
+    private static native void nSetXfermode(long paintPtr, long xfermodePtr);
+    @CriticalNative
     private static native long nSetPathEffect(long paintPtr, long effect);
     @CriticalNative
     private static native long nSetMaskFilter(long paintPtr, long maskfilter);
diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java
index ff9ff8b..83d0507 100644
--- a/graphics/java/android/graphics/PorterDuffXfermode.java
+++ b/graphics/java/android/graphics/PorterDuffXfermode.java
@@ -29,6 +29,9 @@
      *
      * @param mode           The porter-duff mode that is applied
      */
+    static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
+    int porterDuffMode = DEFAULT;
+    PorterDuffXfermode() {}
     public PorterDuffXfermode(PorterDuff.Mode mode) {
         porterDuffMode = mode.nativeInt;
     }
diff --git a/graphics/java/android/graphics/RuntimeColorFilter.java b/graphics/java/android/graphics/RuntimeColorFilter.java
index 52724ce..d112f71 100644
--- a/graphics/java/android/graphics/RuntimeColorFilter.java
+++ b/graphics/java/android/graphics/RuntimeColorFilter.java
@@ -283,6 +283,23 @@
         nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance());
     }
 
+    /**
+     * Assigns the uniform xfermode to the provided xfermode parameter.  If the shader program does
+     * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+     *
+     * @param xfermodeName name matching the uniform declared in the AGSL program
+     * @param xfermode filter passed into the AGSL program for sampling
+     */
+    public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+        if (xfermodeName == null) {
+            throw new NullPointerException("The xfermodeName parameter must not be null");
+        }
+        if (xfermode == null) {
+            throw new NullPointerException("The xfermode parameter must not be null");
+        }
+        nativeUpdateChild(getNativeInstance(), xfermodeName, xfermode.createNativeInstance());
+    }
+
     /** @hide */
     @Override
     protected long createNativeInstance() {
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 78d257f..6316c1f 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -18,10 +18,13 @@
 
 import android.annotation.ColorInt;
 import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.util.ArrayMap;
 import android.view.Window;
 
+import com.android.graphics.hwui.flags.Flags;
+
 import libcore.util.NativeAllocationRegistry;
 
 /**
@@ -525,6 +528,45 @@
         discardNativeInstance();
     }
 
+    /**
+     * Assigns the uniform color filter to the provided color filter parameter.  If the shader
+     * program does not have a uniform color filter with that name then an IllegalArgumentException
+     * is thrown.
+     *
+     * @param filterName name matching the uniform declared in the AGSL program
+     * @param colorFilter filter passed into the AGSL program for sampling
+     */
+    @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+    public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) {
+        if (filterName == null) {
+            throw new NullPointerException("The filterName parameter must not be null");
+        }
+        if (colorFilter == null) {
+            throw new NullPointerException("The colorFilter parameter must not be null");
+        }
+        nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, filterName,
+                colorFilter.getNativeInstance());
+    }
+
+    /**
+     * Assigns the uniform xfermode to the provided xfermode parameter.  If the shader program does
+     * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+     *
+     * @param xfermodeName name matching the uniform declared in the AGSL program
+     * @param xfermode filter passed into the AGSL program for sampling
+     */
+    @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+    public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+        if (xfermodeName == null) {
+            throw new NullPointerException("The xfermodeName parameter must not be null");
+        }
+        if (xfermode == null) {
+            throw new NullPointerException("The xfermode parameter must not be null");
+        }
+        nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, xfermodeName,
+                xfermode.createNativeInstance());
+    }
+
 
     /** @hide */
     @Override
@@ -552,5 +594,7 @@
             int value4, int count);
     private static native void nativeUpdateShader(
             long shaderBuilder, String shaderName, long shader);
+    private static native void nativeUpdateChild(
+            long shaderBuilder, String childName, long child);
 }
 
diff --git a/graphics/java/android/graphics/RuntimeXfermode.java b/graphics/java/android/graphics/RuntimeXfermode.java
new file mode 100644
index 0000000..51d97a4
--- /dev/null
+++ b/graphics/java/android/graphics/RuntimeXfermode.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.ColorInt;
+import android.annotation.ColorLong;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+
+import com.android.graphics.hwui.flags.Flags;
+
+import libcore.util.NativeAllocationRegistry;
+
+
+/**
+ * <p>A {@link RuntimeXfermode} calculates a per-pixel color based on the output of a user
+ *  * defined Android Graphics Shading Language (AGSL) function.</p>
+ *
+ * <p>This AGSL function takes in two input colors to be operated on. These colors are in sRGB
+ *  * and the output is also interpreted as sRGB. The AGSL function signature expects a single input
+ *  * of color (packed as a half4 or float4 or vec4).</p>
+ *
+ * <pre class="prettyprint">
+ * vec4 main(half4 src, half4 dst);
+ * </pre>
+ */
+@FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS)
+public class RuntimeXfermode extends Xfermode {
+
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                        RuntimeXfermode.class.getClassLoader(), nativeGetFinalizer());
+    }
+
+    private long mBuilderNativeInstance;
+
+    /**
+     * Creates a new RuntimeBlender.
+     *
+     * @param agsl The text of AGSL color filter program to run.
+     */
+    public RuntimeXfermode(@NonNull String agsl) {
+        if (agsl == null) {
+            throw new NullPointerException("RuntimeShader requires a non-null AGSL string");
+        }
+        mBuilderNativeInstance = nativeCreateBlenderBuilder(agsl);
+        RuntimeXfermode.NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mBuilderNativeInstance);
+    }
+    /**
+     * Sets the uniform color value corresponding to this color filter.  If the effect does not have
+     * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+     * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the color uniform declared in the AGSL program
+     * @param color the provided sRGB color
+     */
+    public void setColorUniform(@NonNull String uniformName, @ColorInt int color) {
+        setUniform(uniformName, Color.valueOf(color).getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to this color filter.  If the effect does not have
+     * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+     * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the color uniform declared in the AGSL program
+     * @param color the provided sRGB color
+     */
+    public void setColorUniform(@NonNull String uniformName, @ColorLong long color) {
+        Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+        setUniform(uniformName, exSRGB.getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to this color filter.  If the effect does not have
+     * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4
+     * and corresponding layout(color) annotation then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the color uniform declared in the AGSL program
+     * @param color the provided sRGB color
+     */
+    public void setColorUniform(@NonNull String uniformName, @NonNull Color color) {
+        if (color == null) {
+            throw new NullPointerException("The color parameter must not be null");
+        }
+        Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+        setUniform(uniformName, exSRGB.getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than a float or
+     * float[1] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setFloatUniform(@NonNull String uniformName, float value) {
+        setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than a vec2 or
+     * float[2] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setFloatUniform(@NonNull String uniformName, float value1, float value2) {
+        setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than a vec3 or
+     * float[3] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+            float value3) {
+        setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3);
+
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than a vec4 or
+     * float[4] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+            float value3, float value4) {
+        setFloatUniform(uniformName, value1, value2, value3, value4, 4);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than a float
+     * (for N=1), vecN, or float[N] where N is the length of the values param then an
+     * IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) {
+        setUniform(uniformName, values, false);
+    }
+
+    private void setFloatUniform(@NonNull String uniformName, float value1, float value2,
+            float value3, float value4, int count) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4,
+                count);
+    }
+
+    private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        if (values == null) {
+            throw new NullPointerException("The uniform values parameter must not be null");
+        }
+        nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values, isColor);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than an int or int[1]
+     * then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setIntUniform(@NonNull String uniformName, int value) {
+        setIntUniform(uniformName, value, 0, 0, 0, 1);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than an ivec2 or
+     * int[2] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setIntUniform(@NonNull String uniformName, int value1, int value2) {
+        setIntUniform(uniformName, value1, value2, 0, 0, 2);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than an ivec3 or
+     * int[3] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) {
+        setIntUniform(uniformName, value1, value2, value3, 0, 3);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than an ivec4 or
+     * int[4] then an IllegalArgumentException is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setIntUniform(@NonNull String uniformName, int value1, int value2,
+            int value3, int value4) {
+        setIntUniform(uniformName, value1, value2, value3, value4, 4);
+    }
+
+    /**
+     * Sets the uniform value corresponding to this color filter.  If the effect does not have a
+     * uniform with that name or if the uniform is declared with a type other than an int (for N=1),
+     * ivecN, or int[N] where N is the length of the values param then an IllegalArgumentException
+     * is thrown.
+     *
+     * @param uniformName name matching the uniform declared in the AGSL program
+     */
+    public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        if (values == null) {
+            throw new NullPointerException("The uniform values parameter must not be null");
+        }
+        nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values);
+    }
+
+    private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3,
+            int value4, int count) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4,
+                count);
+    }
+
+    /**
+     * Assigns the uniform shader to the provided shader parameter.  If the shader program does not
+     * have a uniform shader with that name then an IllegalArgumentException is thrown.
+     *
+     * @param shaderName name matching the uniform declared in the AGSL program
+     * @param shader shader passed into the AGSL program for sampling
+     */
+    public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
+        if (shaderName == null) {
+            throw new NullPointerException("The shaderName parameter must not be null");
+        }
+        if (shader == null) {
+            throw new NullPointerException("The shader parameter must not be null");
+        }
+        nativeUpdateChild(mBuilderNativeInstance, shaderName, shader.getNativeInstance());
+    }
+
+    /**
+     * Assigns the uniform color filter to the provided color filter parameter.  If the shader
+     * program does not have a uniform color filter with that name then an IllegalArgumentException
+     * is thrown.
+     *
+     * @param filterName name matching the uniform declared in the AGSL program
+     * @param colorFilter filter passed into the AGSL program for sampling
+     */
+    public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) {
+        if (filterName == null) {
+            throw new NullPointerException("The filterName parameter must not be null");
+        }
+        if (colorFilter == null) {
+            throw new NullPointerException("The colorFilter parameter must not be null");
+        }
+        nativeUpdateChild(mBuilderNativeInstance, filterName, colorFilter.getNativeInstance());
+    }
+
+    /**
+     * Assigns the uniform xfermode to the provided xfermode parameter.  If the shader program does
+     * not have a uniform xfermode with that name then an IllegalArgumentException is thrown.
+     *
+     * @param xfermodeName name matching the uniform declared in the AGSL program
+     * @param xfermode xfermode function passed into the AGSL program for sampling
+     */
+    public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) {
+        if (xfermodeName == null) {
+            throw new NullPointerException("The xfermodeName parameter must not be null");
+        }
+        if (xfermode == null) {
+            throw new NullPointerException("The xfermode parameter must not be null");
+        }
+        nativeUpdateChild(mBuilderNativeInstance, xfermodeName, xfermode.createNativeInstance());
+    }
+
+    /** @hide */
+    public long createNativeInstance() {
+        return nativeCreateNativeInstance(mBuilderNativeInstance);
+    }
+
+    /** @hide */
+    private static native long nativeGetFinalizer();
+    private static native long nativeCreateBlenderBuilder(String agsl);
+    private static native long nativeCreateNativeInstance(long builder);
+    private static native void nativeUpdateUniforms(
+            long builder, String uniformName, float[] uniforms, boolean isColor);
+    private static native void nativeUpdateUniforms(
+            long builder, String uniformName, float value1, float value2, float value3,
+            float value4, int count);
+    private static native void nativeUpdateUniforms(
+            long builder, String uniformName, int[] uniforms);
+    private static native void nativeUpdateUniforms(
+            long builder, String uniformName, int value1, int value2, int value3,
+            int value4, int count);
+    private static native void nativeUpdateChild(long builder, String childName, long child);
+
+}
diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java
index 6bb22a1..fb689e4 100644
--- a/graphics/java/android/graphics/Xfermode.java
+++ b/graphics/java/android/graphics/Xfermode.java
@@ -21,9 +21,6 @@
 
 package android.graphics;
 
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-
 /**
  * Xfermode is the base class for objects that are called to implement custom
  * "transfer-modes" in the drawing pipeline. The static function Create(Modes)
@@ -31,8 +28,4 @@
  * specified in the Modes enum. When an Xfermode is assigned to a Paint, then
  * objects drawn with that paint have the xfermode applied.
  */
-public class Xfermode {
-    static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    int porterDuffMode = DEFAULT;
-}
+public class Xfermode {}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
index 220fc6f..819cf34 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java
@@ -94,7 +94,6 @@
      */
     void scheduleBackup() {
         if (!mSaveEmbeddingState) {
-            // TODO(b/289875940): enabled internally for broader testing.
             return;
         }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
index cb280c5..0f1246c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java
@@ -44,7 +44,6 @@
     @NonNull
     private final IBinder mSecondaryContainerToken;
 
-    // TODO(b/289875940): making this as non-null once the tag can be auto-generated from the rule.
     @Nullable
     final String mSplitRuleTag;
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
index a79a89a..bf342d7 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java
@@ -25,6 +25,9 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * This class holds the Parcelable data of a {@link TaskFragmentContainer}.
  */
@@ -61,6 +64,12 @@
     @NonNull
     final Rect mLastRequestedBounds;
 
+    /**
+     * Individual associated activity tokens in different containers that should be finished on
+     * exit.
+     */
+    final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
+
     ParcelableTaskFragmentContainerData(@NonNull IBinder token, @Nullable String overlayTag,
             @Nullable IBinder associatedActivityToken) {
         mToken = token;
@@ -74,6 +83,7 @@
         mOverlayTag = in.readString();
         mAssociatedActivityToken = in.readStrongBinder();
         mLastRequestedBounds = in.readTypedObject(Rect.CREATOR);
+        in.readBinderList(mActivitiesToFinishOnExit);
     }
 
     public static final Creator<ParcelableTaskFragmentContainerData> CREATOR = new Creator<>() {
@@ -99,7 +109,7 @@
         dest.writeString(mOverlayTag);
         dest.writeStrongBinder(mAssociatedActivityToken);
         dest.writeTypedObject(mLastRequestedBounds, flags);
+        dest.writeBinderList(mActivitiesToFinishOnExit);
     }
-
 }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index faf73c2..5ba30dd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -98,10 +98,20 @@
         mCurrentSplitAttributes = mDefaultSplitAttributes;
 
         if (shouldFinishPrimaryWithSecondary(splitRule)) {
-            mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer);
+            addContainerToFinishOnExitWhenRestore(mSecondaryContainer, mPrimaryContainer);
         }
         if (shouldFinishSecondaryWithPrimary(splitRule)) {
-            mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
+            addContainerToFinishOnExitWhenRestore(mPrimaryContainer, mSecondaryContainer);
+        }
+    }
+
+    private void addContainerToFinishOnExitWhenRestore(
+            @NonNull TaskFragmentContainer containerToAdd,
+            @NonNull TaskFragmentContainer containerToFinish) {
+        // If an activity was already added to be finished after the restoration, then that's it.
+        // Otherwise, add the container to finish on exit.
+        if (!containerToAdd.hasActivityToFinishOnExit(containerToFinish)) {
+            containerToAdd.addContainerToFinishOnExit(containerToFinish);
         }
     }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index dc1d983..b3e003e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -96,12 +96,6 @@
             new ArrayList<>();
 
     /**
-     * Individual associated activity tokens in different containers that should be finished on
-     * exit.
-     */
-    private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
-
-    /**
      * The launch options that was used to create this container. Must not {@link Bundle#isEmpty()}
      * for {@link #isOverlay()} container.
      */
@@ -114,7 +108,6 @@
     /**
      * Windowing mode that was requested last via {@link android.window.WindowContainerTransaction}.
      */
-    // TODO(b/289875940): review this and other field that might need to be moved in the base class.
     @WindowingMode
     private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED;
 
@@ -443,7 +436,7 @@
             // Remove the activity now because there can be a delay before the server callback.
             mInfo.getActivities().remove(activityToken);
         }
-        mActivitiesToFinishOnExit.remove(activityToken);
+        mParcelableData.mActivitiesToFinishOnExit.remove(activityToken);
         finishSelfWithActivityIfNeeded(wct, activityToken);
     }
 
@@ -624,7 +617,20 @@
         if (mIsFinished) {
             return;
         }
-        mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
+        mParcelableData.mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
+    }
+
+    /**
+     * Returns {@code true} if an Activity from the given {@code container} was added to be
+     * finished on exit. Otherwise, return {@code false}.
+     */
+    boolean hasActivityToFinishOnExit(@NonNull TaskFragmentContainer container) {
+        for (IBinder activity : mParcelableData.mActivitiesToFinishOnExit) {
+            if (container.hasActivity(activity)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -634,7 +640,7 @@
         if (mIsFinished) {
             return;
         }
-        mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
+        mParcelableData.mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
     }
 
     /** Removes all dependencies that should be finished when this container is finished. */
@@ -643,7 +649,7 @@
             return;
         }
         mContainersToFinishOnExit.clear();
-        mActivitiesToFinishOnExit.clear();
+        mParcelableData.mActivitiesToFinishOnExit.clear();
     }
 
     /**
@@ -721,7 +727,7 @@
         mContainersToFinishOnExit.clear();
 
         // Finish associated activities
-        for (IBinder activityToken : mActivitiesToFinishOnExit) {
+        for (IBinder activityToken : mParcelableData.mActivitiesToFinishOnExit) {
             final Activity activity = mController.getActivity(activityToken);
             if (activity == null || activity.isFinishing()
                     || controller.shouldRetainAssociatedActivity(this, activity)) {
@@ -729,7 +735,7 @@
             }
             wct.finishActivity(activity.getActivityToken());
         }
-        mActivitiesToFinishOnExit.clear();
+        mParcelableData.mActivitiesToFinishOnExit.clear();
     }
 
     @GuardedBy("mController.mLock")
@@ -1082,7 +1088,7 @@
                 + " pendingAppearedActivities=" + mPendingAppearedActivities
                 + (includeContainersToFinishOnExit ? " containersToFinishOnExit="
                 + containersToFinishOnExitToString() : "")
-                + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit
+                + " activitiesToFinishOnExit=" + mParcelableData.mActivitiesToFinishOnExit
                 + " info=" + mInfo
                 + "}";
     }
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index a18a251..bfd9c81 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -23,7 +23,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingBottom="@dimen/desktop_mode_handle_menu_pill_elevation"
-    android:paddingRight="@dimen/desktop_mode_handle_menu_pill_elevation"
+    android:paddingEnd="@dimen/desktop_mode_handle_menu_pill_elevation"
     android:orientation="vertical">
 
     <LinearLayout
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 249e9a2..7078d66 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -661,4 +661,7 @@
     <dimen name="desktop_windowing_education_promo_height">352dp</dimen>
     <!-- The corner radius of the desktop windowing education promo. -->
     <dimen name="desktop_windowing_education_promo_corner_radius">28dp</dimen>
+
+    <!-- The corner radius of freeform tasks in desktop windowing. -->
+    <dimen name="desktop_windowing_freeform_rounded_corner_radius">16dp</dimen>
 </resources>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
index 03e0ab0..4300e84 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java
@@ -168,6 +168,16 @@
     }
 
     /**
+     * @return The task info for the task in this group with the given {@code taskId}.
+     */
+    @Nullable
+    public TaskInfo getTaskById(int taskId) {
+        return mTasks.stream()
+                .filter(task -> task.taskId == taskId)
+                .findFirst().orElse(null);
+    }
+
+    /**
      * Get all {@link RecentTaskInfo}s grouped together.
      */
     @NonNull
@@ -176,6 +186,14 @@
     }
 
     /**
+     * @return Whether this grouped task contains a task with the given {@code taskId}.
+     */
+    public boolean containsTask(int taskId) {
+        return mTasks.stream()
+                .anyMatch((task -> task.taskId == taskId));
+    }
+
+    /**
      * Return {@link SplitBounds} if this is a split screen entry or {@code null}
      */
     @Nullable
@@ -249,9 +267,10 @@
             return null;
         }
         return "id=" + taskInfo.taskId
-                + " baseIntent=" + (taskInfo.baseIntent != null
-                        ? taskInfo.baseIntent.getComponent()
-                        : "null")
+                + " baseIntent=" +
+                        (taskInfo.baseIntent != null && taskInfo.baseIntent.getComponent() != null
+                                ? taskInfo.baseIntent.getComponent().flattenToString()
+                                : "null")
                 + " winMode=" + WindowConfiguration.windowingModeToString(
                         taskInfo.getWindowingMode());
     }
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
index 23e7441..f14dfdb 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
@@ -50,6 +50,22 @@
     fun createMenu(snapshotList: List<Pair<Int, TaskSnapshot>>,
              onIconClickListener: ((Int) -> Unit),
              onOutsideClickListener: (() -> Unit)): ManageWindowsView {
+        val bitmapList = snapshotList.map { (index, snapshot) ->
+            index to Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
+        }
+        return createAndShowMenuView(
+            bitmapList,
+            onIconClickListener,
+            onOutsideClickListener
+        )
+    }
+
+    /** Creates the menu view with the given bitmaps, and displays it. */
+    fun createAndShowMenuView(
+        snapshotList: List<Pair<Int, Bitmap?>>,
+        onIconClickListener: ((Int) -> Unit),
+        onOutsideClickListener: (() -> Unit)
+    ): ManageWindowsView {
         menuView = ManageWindowsView(context, menuBackgroundColor).apply {
             this.onOutsideClickListener = onOutsideClickListener
             this.onIconClickListener = onIconClickListener
@@ -120,7 +136,7 @@
         }
 
         fun generateIconViews(
-            snapshotList: List<Pair<Int, TaskSnapshot>>
+            snapshotList: List<Pair<Int, Bitmap?>>
         ) {
             menuWidth = 0
             menuHeight = 0
@@ -133,7 +149,7 @@
             // Add each icon to the menu, adding a new row when needed.
             for ((iconCount, taskInfoSnapshotPair) in snapshotList.withIndex()) {
                 val taskId = taskInfoSnapshotPair.first
-                val snapshot = taskInfoSnapshotPair.second
+                val snapshotBitmap = taskInfoSnapshotPair.second
                 // Once a row is filled, make a new row and increase the menu height.
                 if (iconCount % MENU_MAX_ICONS_PER_ROW == 0) {
                     rowLayout = LinearLayout(context)
@@ -141,10 +157,7 @@
                     rootView.addView(rowLayout)
                     menuHeight += (instanceIconHeight + iconMargin).toInt()
                 }
-                val snapshotBitmap = Bitmap.wrapHardwareBuffer(
-                    snapshot.hardwareBuffer,
-                    snapshot.colorSpace
-                )
+
                 val croppedBitmap = snapshotBitmap?.let { cropBitmap(it) }
                 val scaledSnapshotBitmap = croppedBitmap?.let {
                     Bitmap.createScaledBitmap(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 39dc267..603a9ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -2087,8 +2087,9 @@
 
             BubbleLogger.Event event = isExpanded ? BubbleLogger.Event.BUBBLE_BAR_EXPANDED
                     : BubbleLogger.Event.BUBBLE_BAR_COLLAPSED;
-            if (mBubbleData.getSelectedBubble() instanceof Bubble bubble) {
-                mLogger.log(bubble, event);
+            BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
+            if (selectedBubble instanceof Bubble) {
+                mLogger.log((Bubble) selectedBubble, event);
             } else {
                 mLogger.log(event);
             }
@@ -2099,8 +2100,9 @@
             // Only need to update the layer view if we're currently expanded for selection changes.
             if (mLayerView != null && mLayerView.isExpanded()) {
                 mLayerView.showExpandedView(selectedBubble);
-                if (selectedBubble instanceof Bubble bubble) {
-                    mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
+                if (selectedBubble instanceof Bubble) {
+                    mLogger.log((Bubble) selectedBubble,
+                            BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
                 }
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index f532be6..12d20bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -96,6 +96,14 @@
     }
 
     /**
+     * Get all the displays from DisplayManager.
+     */
+    public Display[] getDisplays() {
+        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        return displayManager.getDisplays();
+    }
+
+    /**
      * Gets the DisplayLayout associated with a display.
      */
     public @Nullable DisplayLayout getDisplayLayout(int displayId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt
new file mode 100644
index 0000000..819b110
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.content.Context
+import android.graphics.Color
+import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellCommandHandler.ShellCommandActionHandler
+import com.android.wm.shell.sysui.ShellInit
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Handles the shell commands for the CompatUI.
+ *
+ * <p> Use with [adb shell dumpsys activity service SystemUIService WMShell letterbox
+ * &lt;command&gt;].
+ */
+@WMSingleton
+class LetterboxCommandHandler @Inject constructor(
+    private val context: Context,
+    shellInit: ShellInit,
+    shellCommandHandler: ShellCommandHandler,
+    private val letterboxConfiguration: LetterboxConfiguration
+) : ShellCommandActionHandler {
+
+    companion object {
+        @JvmStatic
+        private val TAG = "LetterboxCommandHandler"
+    }
+
+    init {
+        if (Flags.appCompatRefactoring()) {
+            ProtoLog.v(
+                WM_SHELL_APP_COMPAT,
+                "%s: %s",
+                TAG,
+                "Initializing LetterboxCommandHandler"
+            )
+            shellInit.addInitCallback({
+                shellCommandHandler.addCommandCallback("letterbox", this, this)
+            }, this)
+        }
+    }
+
+    override fun onShellCommand(args: Array<out String>?, pw: PrintWriter?): Boolean {
+        if (args == null || pw == null) {
+            pw!!.println("Missing arguments.")
+            return false
+        }
+        return when (args.size) {
+            1 -> onShellDisplayCommand(args[0], pw)
+            2 -> onShellUpdateCommand(args[0], args[1], pw)
+            else -> {
+                pw.println("Invalid command: " + args[0])
+                return false
+            }
+        }
+    }
+
+    override fun printShellCommandHelp(pw: PrintWriter?, prefix: String?) {
+        pw?.println(
+            """
+                    $prefix backgroundColor color"
+                    $prefix      Color of letterbox which is to be used when letterbox background
+                    $prefix      type is 'solid-color'. See Color#parseColor for allowed color
+                    $prefix      formats (#RRGGBB and some colors by name, e.g. magenta or olive).
+                    $prefix backgroundColorResource resource_name"
+                    $prefix      Color resource name of letterbox background which is used when
+                    $prefix      background type is 'solid-color'. Parameter is a color resource
+                    $prefix      name, for example, @android:color/system_accent2_50.
+                    $prefix backgroundColorReset"
+                    $prefix      Resets the background color to the default value."
+                """.trimIndent()
+        )
+    }
+
+    private fun onShellUpdateCommand(command: String, value: String, pw: PrintWriter): Boolean {
+        when (command) {
+            "backgroundColor" -> {
+                return invokeWhenValid(
+                    pw,
+                    value,
+                    ::strToColor,
+                    { color ->
+                        letterboxConfiguration.setLetterboxBackgroundColor(color)
+                    },
+                    { c -> "$c is not a valid color." }
+                )
+            }
+
+            "backgroundColorResource" -> return invokeWhenValid(
+                pw,
+                value,
+                ::nameToColorId,
+                { color ->
+                    letterboxConfiguration.setLetterboxBackgroundColorResourceId(color)
+                },
+                { c ->
+                    "$c is not a valid resource. Color in '@android:color/resource_name'" +
+                            " format should be provided as an argument."
+                }
+            )
+
+            "backgroundColorReset" -> {
+                letterboxConfiguration.resetLetterboxBackgroundColor()
+                return true
+            }
+
+            else -> {
+                pw.println("Invalid command: $value")
+                return false
+            }
+        }
+    }
+
+    private fun onShellDisplayCommand(command: String, pw: PrintWriter): Boolean {
+        when (command) {
+            "backgroundColor" -> {
+                pw.println(
+                    "    Background color: " + Integer.toHexString(
+                        letterboxConfiguration.getLetterboxBackgroundColor()
+                            .toArgb()
+                    )
+                )
+                return true
+            }
+
+            else -> {
+                pw.println("Invalid command: $command")
+                return false
+            }
+        }
+    }
+
+    private fun <T> invokeWhenValid(
+        pw: PrintWriter,
+        input: String,
+        converter: (String) -> T?,
+        consumer: (T) -> Unit,
+        errorMessage: (String) -> String = { value -> " Wrong input value: $value." }
+    ): Boolean {
+        converter(input)?.let {
+            consumer(it)
+            return true
+        }
+        pw.println(errorMessage(input))
+        return false
+    }
+
+    // Converts a String to Color if possible or it returns null otherwise.
+    private fun strToColor(str: String): Color? =
+        try {
+            Color.valueOf(Color.parseColor(str))
+        } catch (e: IllegalArgumentException) {
+            null
+        }
+
+    // Converts a resource id to Color if possible or it returns null otherwise.
+    private fun nameToColorId(str: String): Int? =
+        try {
+            context.resources.getIdentifier(str, "color", "com.android.internal")
+        } catch (e: IllegalArgumentException) {
+            null
+        }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt
new file mode 100644
index 0000000..83a8e31
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.annotation.ColorRes
+import android.content.Context
+import android.graphics.Color
+import com.android.internal.R
+import com.android.wm.shell.dagger.WMSingleton
+import javax.inject.Inject
+
+/**
+ * Contains configuration properties for the letterbox implementation in Shell.
+ */
+@WMSingleton
+class LetterboxConfiguration @Inject constructor(
+    private val context: Context
+) {
+    // Color to use for the solid color letterbox background type.
+    private var letterboxBackgroundColorOverride: Color? = null
+
+    // Color resource id for the solid color letterbox background type.
+    private var letterboxBackgroundColorResourceIdOverride: Int? = null
+
+    /**
+     * Sets color of letterbox background which is used when using the solid background mode.
+     */
+    fun setLetterboxBackgroundColor(color: Color) {
+        letterboxBackgroundColorOverride = color
+    }
+
+    /**
+     * Sets color ID of letterbox background which is used when using the solid background mode.
+     */
+    fun setLetterboxBackgroundColorResourceId(@ColorRes colorId: Int) {
+        letterboxBackgroundColorResourceIdOverride = colorId
+    }
+
+    /**
+     * Gets color of letterbox background which is used when the solid color mode is active.
+     */
+    fun getLetterboxBackgroundColor(): Color {
+        if (letterboxBackgroundColorOverride != null) {
+            return letterboxBackgroundColorOverride!!
+        }
+        val colorId = if (letterboxBackgroundColorResourceIdOverride != null) {
+            letterboxBackgroundColorResourceIdOverride
+        } else {
+            R.color.config_letterboxBackgroundColor
+        }
+        // Query color dynamically because material colors extracted from wallpaper are updated
+        // when wallpaper is changed.
+        return Color.valueOf(context.getResources().getColor(colorId!!, /* theme */null))
+    }
+
+    /**
+     * Resets color of letterbox background to the default.
+     */
+    fun resetLetterboxBackgroundColor() {
+        letterboxBackgroundColorOverride = null
+        letterboxBackgroundColorResourceIdOverride = null
+    }
+
+    /**
+     * The background color for the Letterbox.
+     */
+    fun getBackgroundColorRgbArray(): FloatArray = getLetterboxBackgroundColor().components
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
new file mode 100644
index 0000000..0ac7aff
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.graphics.Rect
+import android.view.SurfaceControl
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.dagger.WMSingleton
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import javax.inject.Inject
+
+/**
+ * Component responsible for handling the lifecycle of the letterbox surfaces.
+ */
+@WMSingleton
+class LetterboxController @Inject constructor(
+    private val letterboxConfiguration: LetterboxConfiguration
+) {
+
+    companion object {
+        /*
+         * Letterbox surfaces need to stay below the activity layer which is 0.
+         */
+        // TODO(b/378673153): Consider adding this to [TaskConstants].
+        @JvmStatic
+        private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000
+        @JvmStatic
+        private val TAG = "LetterboxController"
+    }
+
+    private val letterboxMap = mutableMapOf<LetterboxKey, LetterboxItem>()
+
+    /**
+     * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist.
+     */
+    fun createLetterboxSurface(
+        key: LetterboxKey,
+        startTransaction: SurfaceControl.Transaction,
+        parentLeash: SurfaceControl
+    ) {
+        letterboxMap.runOnItem(key, onMissed = { k, m ->
+            m[k] = LetterboxItem(
+                SurfaceControl.Builder()
+                    .setName("ShellLetterboxSurface-$key")
+                    .setHidden(true)
+                    .setColorLayer()
+                    .setParent(parentLeash)
+                    .setCallsite("LetterboxController-createLetterboxSurface")
+                    .build().apply {
+                        startTransaction.setLayer(
+                            this,
+                            TASK_CHILD_LAYER_LETTERBOX_BACKGROUND
+                        ).setColorSpaceAgnostic(this, true)
+                            .setColor(this, letterboxConfiguration.getBackgroundColorRgbArray())
+                    }
+            )
+        })
+    }
+
+    /**
+     * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId.
+     */
+    fun destroyLetterboxSurface(
+        key: LetterboxKey,
+        startTransaction: SurfaceControl.Transaction
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.fullWindowSurface?.run {
+                startTransaction.remove(this)
+            }
+        })
+        letterboxMap.remove(key)
+    }
+
+    /**
+     * Invoked to show/hide the letterbox surfaces for given displayId/taskId.
+     */
+    fun updateLetterboxSurfaceVisibility(
+        key: LetterboxKey,
+        startTransaction: SurfaceControl.Transaction,
+        visible: Boolean = true
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.fullWindowSurface?.run {
+                startTransaction.setVisibility(this, visible)
+            }
+        })
+    }
+
+    /**
+     * Updates the bounds for the letterbox surfaces for given displayId/taskId.
+     */
+    fun updateLetterboxSurfaceBounds(
+        key: LetterboxKey,
+        startTransaction: SurfaceControl.Transaction,
+        bounds: Rect
+    ) {
+        letterboxMap.runOnItem(key, onFound = { item ->
+            item.fullWindowSurface?.run {
+                startTransaction.moveAndCrop(this, bounds)
+            }
+        })
+    }
+
+    /*
+     * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present.
+     */
+    private fun MutableMap<LetterboxKey, LetterboxItem>.runOnItem(
+        key: LetterboxKey,
+        onFound: (LetterboxItem) -> Unit = { _ -> },
+        onMissed: (
+            LetterboxKey,
+            MutableMap<LetterboxKey, LetterboxItem>
+        ) -> Unit = { _, _ -> }
+    ) {
+        this[key]?.let {
+            return onFound(it)
+        }
+        return onMissed(key, this)
+    }
+
+    fun dump() {
+        ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}")
+    }
+
+    private fun SurfaceControl.Transaction.moveAndCrop(
+        surface: SurfaceControl,
+        rect: Rect
+    ): SurfaceControl.Transaction =
+        setPosition(surface, rect.left.toFloat(), rect.top.toFloat())
+            .setWindowCrop(
+                surface,
+                rect.width(),
+                rect.height()
+            )
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
new file mode 100644
index 0000000..98fd247
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.view.SurfaceControl
+
+// The key to use for identify the letterbox sessions.
+data class LetterboxKey(val displayId: Int, val taskId: Int)
+
+// Encapsulate the objects for the specific letterbox session.
+data class LetterboxItem(val fullWindowSurface: SurfaceControl?)
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
new file mode 100644
index 0000000..67429bd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.graphics.Rect
+import android.os.IBinder
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags.appCompatRefactoring
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT
+import com.android.wm.shell.shared.TransitionUtil.isClosingType
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+
+/**
+ * The [TransitionObserver] to handle Letterboxing events in Shell.
+ */
+class LetterboxTransitionObserver(
+    shellInit: ShellInit,
+    private val transitions: Transitions,
+    private val letterboxController: LetterboxController
+) : Transitions.TransitionObserver {
+
+    companion object {
+        @JvmStatic
+        private val TAG = "LetterboxTransitionObserver"
+    }
+
+    init {
+        if (appCompatRefactoring()) {
+            ProtoLog.v(
+                WM_SHELL_APP_COMPAT,
+                "%s: %s",
+                TAG,
+                "Initializing LetterboxTransitionObserver"
+            )
+            shellInit.addInitCallback({
+                transitions.registerObserver(this)
+            }, this)
+        }
+    }
+
+    override fun onTransitionReady(
+        transition: IBinder,
+        info: TransitionInfo,
+        startTransaction: SurfaceControl.Transaction,
+        finishTransaction: SurfaceControl.Transaction
+    ) {
+        // We recognise the operation to execute and delegate to the LetterboxController
+        // the related operation.
+        // TODO(b/377875151): Identify Desktop Windowing Transactions.
+        // TODO(b/377857898): Handling multiple surfaces
+        // TODO(b/371500295): Handle input events detection.
+        for (change in info.changes) {
+            change.taskInfo?.let { ti ->
+                val key = LetterboxKey(ti.displayId, ti.taskId)
+                if (isClosingType(change.mode)) {
+                    letterboxController.destroyLetterboxSurface(
+                        key,
+                        startTransaction
+                    )
+                } else {
+                    val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed
+                    if (isTopActivityLetterboxed) {
+                        letterboxController.createLetterboxSurface(
+                            key,
+                            startTransaction,
+                            change.leash
+                        )
+                        letterboxController.updateLetterboxSurfaceBounds(
+                            key,
+                            startTransaction,
+                            Rect(
+                                change.endRelOffset.x,
+                                change.endRelOffset.y,
+                                change.endAbsBounds.width(),
+                                change.endAbsBounds.height()
+                            )
+                        )
+                    }
+                    letterboxController.updateLetterboxSurfaceVisibility(
+                        key,
+                        startTransaction,
+                        isTopActivityLetterboxed
+                    )
+                }
+                letterboxController.dump()
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 77e041e..02df38e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -795,13 +795,14 @@
     static KeyguardTransitionHandler provideKeyguardTransitionHandler(
             ShellInit shellInit,
             ShellController shellController,
+            DisplayController displayController,
             Transitions transitions,
             TaskStackListenerImpl taskStackListener,
             @ShellMainThread Handler mainHandler,
             @ShellMainThread ShellExecutor mainExecutor) {
         return new KeyguardTransitionHandler(
-                shellInit, shellController, transitions, taskStackListener, mainHandler,
-                mainExecutor);
+                shellInit, shellController, displayController, transitions, taskStackListener,
+                mainHandler, mainExecutor);
     }
 
     @WMSingleton
@@ -1024,10 +1025,13 @@
     @WMSingleton
     @Provides
     static TaskStackTransitionObserver provideTaskStackTransitionObserver(
-            Lazy<Transitions> transitions,
-            ShellInit shellInit
+            ShellInit shellInit,
+            Lazy<ShellTaskOrganizer> shellTaskOrganizer,
+            ShellCommandHandler shellCommandHandler,
+            Lazy<Transitions> transitions
     ) {
-        return new TaskStackTransitionObserver(transitions, shellInit);
+        return new TaskStackTransitionObserver(shellInit, shellTaskOrganizer, shellCommandHandler,
+                transitions);
     }
 
     //
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 601cf70..96f8024 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -20,6 +20,10 @@
 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
 import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS;
 
+import static com.android.hardware.input.Flags.manageKeyGestures;
+import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.content.Context;
@@ -62,6 +66,9 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler;
+import com.android.wm.shell.compatui.letterbox.LetterboxController;
+import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver;
 import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
 import com.android.wm.shell.dagger.pip.PipModule;
 import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler;
@@ -73,6 +80,7 @@
 import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler;
 import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler;
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
+import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler;
 import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
 import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
@@ -755,8 +763,6 @@
                 dragToDesktopTransitionHandler,
                 desktopImmersiveController.get(),
                 desktopRepository,
-                desktopModeLoggerTransitionObserver,
-                launchAdjacentController,
                 recentsTransitionHandler,
                 multiInstanceHelper,
                 mainExecutor,
@@ -764,8 +770,6 @@
                 recentTasksController.orElse(null),
                 interactionJankMonitor,
                 mainHandler,
-                inputManager,
-                focusTransitionObserver,
                 desktopModeEventLogger,
                 desktopTilingDecorViewModel);
     }
@@ -880,6 +884,72 @@
 
     @WMSingleton
     @Provides
+    static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler(
+            Context context,
+            Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
+            Optional<DesktopTasksController> desktopTasksController,
+            InputManager inputManager,
+            ShellTaskOrganizer shellTaskOrganizer,
+            FocusTransitionObserver focusTransitionObserver) {
+        if (DesktopModeStatus.canEnterDesktopMode(context) && useKeyGestureEventHandler()
+                && manageKeyGestures()
+                && (Flags.enableMoveToNextDisplayShortcut()
+                || Flags.enableTaskResizingKeyboardShortcuts())) {
+            return Optional.of(new DesktopModeKeyGestureHandler(context,
+                    desktopModeWindowDecorViewModel, desktopTasksController,
+                    inputManager, shellTaskOrganizer, focusTransitionObserver));
+        }
+        return Optional.empty();
+    }
+
+    @WMSingleton
+    @Provides
+    static Optional<DesktopModeWindowDecorViewModel> provideDesktopModeWindowDecorViewModel(
+            Context context,
+            @ShellMainThread ShellExecutor shellExecutor,
+            @ShellMainThread Handler mainHandler,
+            Choreographer mainChoreographer,
+            @ShellBackgroundThread ShellExecutor bgExecutor,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            IWindowManager windowManager,
+            ShellTaskOrganizer taskOrganizer,
+            @DynamicOverride DesktopRepository desktopRepository,
+            DisplayController displayController,
+            ShellController shellController,
+            DisplayInsetsController displayInsetsController,
+            SyncTransactionQueue syncQueue,
+            Transitions transitions,
+            Optional<DesktopTasksController> desktopTasksController,
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            InteractionJankMonitor interactionJankMonitor,
+            AppToWebGenericLinksParser genericLinksParser,
+            AssistContentRequester assistContentRequester,
+            MultiInstanceHelper multiInstanceHelper,
+            Optional<DesktopTasksLimiter> desktopTasksLimiter,
+            AppHandleEducationController appHandleEducationController,
+            AppToWebEducationController appToWebEducationController,
+            WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
+            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
+            FocusTransitionObserver focusTransitionObserver,
+            DesktopModeEventLogger desktopModeEventLogger
+    ) {
+        if (!DesktopModeStatus.canEnterDesktopMode(context)) {
+            return Optional.empty();
+        }
+        return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler,
+                mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager,
+                taskOrganizer, desktopRepository, displayController, shellController,
+                displayInsetsController, syncQueue, transitions, desktopTasksController,
+                rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
+                assistContentRequester, multiInstanceHelper, desktopTasksLimiter,
+                appHandleEducationController, appToWebEducationController,
+                windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
+                focusTransitionObserver, desktopModeEventLogger));
+    }
+
+    @WMSingleton
+    @Provides
     static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
             Transitions transitions,
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
@@ -1229,8 +1299,25 @@
     @Provides
     static Object provideIndependentShellComponentsToCreate(
             DragAndDropController dragAndDropController,
+            @NonNull LetterboxTransitionObserver letterboxTransitionObserver,
+            @NonNull LetterboxCommandHandler letterboxCommandHandler,
             Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional,
-            Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler) {
+            Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler,
+            Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler) {
         return new Object();
     }
+
+    //
+    // App Compat
+    //
+
+    @WMSingleton
+    @Provides
+    static LetterboxTransitionObserver provideLetterboxTransitionObserver(
+            @NonNull ShellInit shellInit,
+            @NonNull Transitions transitions,
+            @NonNull LetterboxController letterboxController
+    ) {
+        return new LetterboxTransitionObserver(shellInit, transitions, letterboxController);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index 2001f97..82c2ebc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -23,6 +23,7 @@
 import android.os.IBinder
 import android.view.SurfaceControl
 import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_OPEN
 import android.window.DesktopModeFlags
 import android.window.TransitionInfo
 import android.window.TransitionInfo.Change
@@ -95,7 +96,7 @@
     fun startLaunchTransition(
         @WindowManager.TransitionType transitionType: Int,
         wct: WindowContainerTransaction,
-        taskId: Int,
+        taskId: Int?,
         minimizingTaskId: Int? = null,
         exitingImmersiveTask: Int? = null,
     ): IBinder {
@@ -216,12 +217,12 @@
     ): Boolean {
         // Check if there's also an immersive change during this launch.
         val immersiveExitChange = pending.exitingImmersiveTask?.let { exitingTask ->
-            findDesktopTaskChange(info, exitingTask)
+            findTaskChange(info, exitingTask)
         }
         val minimizeChange = pending.minimizingTask?.let { minimizingTask ->
-            findDesktopTaskChange(info, minimizingTask)
+            findTaskChange(info, minimizingTask)
         }
-        val launchChange = findDesktopTaskChange(info, pending.launchingTask)
+        val launchChange = findDesktopTaskLaunchChange(info, pending.launchingTask)
         if (launchChange == null) {
             check(minimizeChange == null)
             check(immersiveExitChange == null)
@@ -291,7 +292,7 @@
     ): Boolean {
         if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false
 
-        val minimizeChange = findDesktopTaskChange(info, pending.minimizingTask)
+        val minimizeChange = findTaskChange(info, pending.minimizingTask)
         if (minimizeChange == null) {
             logW("Should have minimizing desktop task")
             return false
@@ -417,8 +418,24 @@
         }
     }
 
-    private fun findDesktopTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? {
-        return info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId }
+    private fun findTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? =
+        info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId }
+
+    private fun findDesktopTaskLaunchChange(
+        info: TransitionInfo,
+        launchTaskId: Int?
+    ): TransitionInfo.Change? {
+        return if (launchTaskId != null) {
+            // Launching a known task (probably from background or moving to front), so
+            // specifically look for it.
+            findTaskChange(info, launchTaskId)
+        } else {
+            // Launching a new task, so the first opening freeform task.
+            info.changes.firstOrNull { change ->
+                change.mode == TRANSIT_OPEN
+                        && change.taskInfo != null && change.taskInfo!!.isFreeform
+            }
+        }
     }
 
     private fun WindowContainerTransaction?.merge(
@@ -441,7 +458,7 @@
         /** A task is opening or moving to front. */
         data class Launch(
             override val transition: IBinder,
-            val launchingTask: Int,
+            val launchingTask: Int?,
             val minimizingTask: Int?,
             val exitingImmersiveTask: Int?,
         ) : PendingMixedTransition()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
new file mode 100644
index 0000000..ac07eaa
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.hardware.input.KeyGestureEvent
+
+import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyGestureEventHandler
+import android.os.IBinder
+import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.wm.shell.ShellTaskOrganizer
+import android.app.ActivityManager.RunningTaskInfo
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
+import com.android.internal.protolog.ProtoLog
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.Context
+import com.android.hardware.input.Flags.manageKeyGestures
+import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.transition.FocusTransitionObserver
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import java.util.Optional
+
+/**
+ * Handles key gesture events (keyboard shortcuts) in Desktop Mode.
+ */
+class DesktopModeKeyGestureHandler(
+    private val context: Context,
+    private val desktopModeWindowDecorViewModel: Optional<DesktopModeWindowDecorViewModel>,
+    private val desktopTasksController: Optional<DesktopTasksController>,
+    inputManager: InputManager,
+    private val shellTaskOrganizer: ShellTaskOrganizer,
+    private val focusTransitionObserver: FocusTransitionObserver,
+    ) : KeyGestureEventHandler {
+
+    init {
+        inputManager.registerKeyGestureEventHandler(this)
+    }
+
+    override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean {
+        if (!isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent
+            || !desktopModeWindowDecorViewModel.isPresent) {
+            return false
+        }
+        when (event.keyGestureType) {
+            KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
+                logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().moveToNextDisplay(
+                        it.taskId
+                    )
+                }
+                return true
+            }
+            // TODO(b/375356876): Modify function to pass in keyboard shortcut as the input
+            // method for logging task resize
+            KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> {
+                logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopModeWindowDecorViewModel.get().onSnapResize(
+                        it.taskId,
+                        true,
+                        null
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> {
+                logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopModeWindowDecorViewModel.get().onSnapResize(
+                        it.taskId,
+                        false,
+                        null
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> {
+                logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().toggleDesktopTaskSize(
+                        it,
+                        ResizeTrigger.MAXIMIZE_MENU,
+                        null,
+                    )
+                }
+                return true
+            }
+            KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> {
+                logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled")
+                getGloballyFocusedFreeformTask()?.let {
+                    desktopTasksController.get().minimizeTask(
+                        it,
+                    )
+                }
+                return true
+            }
+            else -> return false
+        }
+    }
+
+    override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) {
+        KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
+            -> enableMoveToNextDisplayShortcut()
+        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
+        KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+            -> enableTaskResizingKeyboardShortcuts() && manageKeyGestures()
+        else -> false
+    }
+
+    //  TODO: b/364154795 - wait for the completion of moveToNextDisplay transition, otherwise it
+    //  will pick a wrong task when a user quickly perform other actions with keyboard shortcuts
+    //  after moveToNextDisplay, and move this to FocusTransitionObserver class.
+    private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? =
+        shellTaskOrganizer.getRunningTasks().find { taskInfo ->
+            taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
+                    focusTransitionObserver.hasGlobalFocus(taskInfo)
+        }
+
+    private fun logV(msg: String, vararg arguments: Any?) {
+        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+    }
+
+    companion object {
+        private const val TAG = "DesktopModeKeyGestureHandler"
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 08ca55f..7fcb767 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -411,6 +411,12 @@
             desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.toDumpString())
         // Remove task from unminimized task if it is minimized.
         unminimizeTask(displayId, taskId)
+        // Mark task as not in immersive if it was immersive.
+        setTaskInFullImmersiveState(
+            displayId = displayId,
+            taskId = taskId,
+            immersive = false
+        )
         removeActiveTask(taskId)
         removeVisibleTask(taskId)
         if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
@@ -487,6 +493,9 @@
             mainCoroutineScope.launch {
                 try {
                     persistentRepository.addOrUpdateDesktop(
+                        // Use display id as desktop id for now since only once desktop per display
+                        // is supported.
+                        desktopId = displayId,
                         visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks,
                         minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks,
                         freeformTasksInZOrder = desktopTaskDataByDisplayIdCopy.freeformTasksInZOrder
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 7446b88..8bad874 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
@@ -35,9 +35,6 @@
 import android.graphics.PointF
 import android.graphics.Rect
 import android.graphics.Region
-import android.hardware.input.InputManager
-import android.hardware.input.InputManager.KeyGestureEventHandler
-import android.hardware.input.KeyGestureEvent
 import android.os.Binder
 import android.os.Handler
 import android.os.IBinder
@@ -46,7 +43,6 @@
 import android.util.Size
 import android.view.Display.DEFAULT_DISPLAY
 import android.view.DragEvent
-import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.SurfaceControl
 import android.view.SurfaceControl.Transaction
@@ -66,7 +62,6 @@
 import android.window.TransitionRequestInfo
 import android.window.WindowContainerTransaction
 import androidx.annotation.BinderThread
-import com.android.hardware.input.Flags.useKeyGestureEventHandler
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
 import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
@@ -75,13 +70,12 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.internal.protolog.ProtoLog
 import com.android.window.flags.Flags
-import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ExternalInterfaceBinder
-import com.android.wm.shell.common.LaunchAdjacentController
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent
 import com.android.wm.shell.common.RemoteCallable
@@ -89,7 +83,6 @@
 import com.android.wm.shell.common.SingleInstanceRemoteListener
 import com.android.wm.shell.common.SyncTransactionQueue
 import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
-import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
 import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
 import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener
@@ -117,7 +110,6 @@
 import com.android.wm.shell.sysui.ShellController
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.sysui.UserChangeListener
-import com.android.wm.shell.transition.FocusTransitionObserver
 import com.android.wm.shell.transition.OneShotRemoteHandler
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
@@ -157,8 +149,6 @@
     private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler,
     private val desktopImmersiveController: DesktopImmersiveController,
     private val taskRepository: DesktopRepository,
-    private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver,
-    private val launchAdjacentController: LaunchAdjacentController,
     private val recentsTransitionHandler: RecentsTransitionHandler,
     private val multiInstanceHelper: MultiInstanceHelper,
     @ShellMainThread private val mainExecutor: ShellExecutor,
@@ -166,16 +156,13 @@
     private val recentTasksController: RecentTasksController?,
     private val interactionJankMonitor: InteractionJankMonitor,
     @ShellMainThread private val handler: Handler,
-    private val inputManager: InputManager,
-    private val focusTransitionObserver: FocusTransitionObserver,
     private val desktopModeEventLogger: DesktopModeEventLogger,
     private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel,
 ) :
     RemoteCallable<DesktopTasksController>,
     Transitions.TransitionHandler,
     DragAndDropController.DragAndDropListener,
-    UserChangeListener,
-    KeyGestureEventHandler {
+    UserChangeListener {
 
     private val desktopMode: DesktopModeImpl
     private var visualIndicator: DesktopModeVisualIndicator? = null
@@ -249,9 +236,6 @@
             }
         )
         dragAndDropController.addListener(this)
-        if (useKeyGestureEventHandler() && enableMoveToNextDisplayShortcut()) {
-            inputManager.registerKeyGestureEventHandler(this)
-        }
     }
 
     @VisibleForTesting
@@ -618,25 +602,18 @@
     private fun moveBackgroundTaskToFront(taskId: Int, remoteTransition: RemoteTransition?) {
         logV("moveBackgroundTaskToFront taskId=%s", taskId)
         val wct = WindowContainerTransaction()
-        // TODO: b/342378842 - Instead of using default display, support multiple displays
-        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
-            wct = wct,
-            displayId = DEFAULT_DISPLAY,
-            excludeTaskId = taskId,
-        )
         wct.startTask(
             taskId,
             ActivityOptions.makeBasic().apply {
                 launchWindowingMode = WINDOWING_MODE_FREEFORM
             }.toBundle(),
         )
-        val transition = startLaunchTransition(
+        startLaunchTransition(
             TRANSIT_OPEN,
             wct,
             taskId,
             remoteTransition = remoteTransition
         )
-        exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
     }
 
     /**
@@ -655,47 +632,53 @@
         }
         val wct = WindowContainerTransaction()
         wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */)
-        val result = desktopImmersiveController.exitImmersiveIfApplicable(
-            wct = wct,
-            displayId = taskInfo.displayId,
-            excludeTaskId = taskInfo.taskId,
-        )
-        val exitResult = if (result is ExitResult.Exit) { result } else { null }
-        val transition = startLaunchTransition(
+        startLaunchTransition(
             transitionType = TRANSIT_TO_FRONT,
             wct = wct,
-            taskId = taskInfo.taskId,
-            exitingImmersiveTask = exitResult?.exitingTask,
+            launchingTaskId = taskInfo.taskId,
             remoteTransition = remoteTransition,
             displayId = taskInfo.displayId,
         )
-        exitResult?.runOnTransitionStart?.invoke(transition)
     }
 
     private fun startLaunchTransition(
         transitionType: Int,
         wct: WindowContainerTransaction,
-        taskId: Int,
-        exitingImmersiveTask: Int? = null,
+        launchingTaskId: Int?,
         remoteTransition: RemoteTransition? = null,
         displayId: Int = DEFAULT_DISPLAY,
     ): IBinder {
-        val taskIdToMinimize = addAndGetMinimizeChanges(displayId, wct, taskId)
+        val taskIdToMinimize = if (launchingTaskId != null) {
+            addAndGetMinimizeChanges(displayId, wct, newTaskId = launchingTaskId)
+        } else {
+            logW("Starting desktop task launch without checking the task-limit")
+            // TODO(b/378920066): This currently does not respect the desktop window limit.
+            //  It's possible that |launchingTaskId| is null when launching using an intent, and
+            //  the task-limit should be respected then too.
+            null
+        }
+        val exitImmersiveResult = desktopImmersiveController.exitImmersiveIfApplicable(
+            wct = wct,
+            displayId = displayId,
+            excludeTaskId = launchingTaskId,
+        )
         if (remoteTransition == null) {
             val t = desktopMixedTransitionHandler.startLaunchTransition(
                 transitionType = transitionType,
                 wct = wct,
-                taskId = taskId,
+                taskId = launchingTaskId,
                 minimizingTaskId = taskIdToMinimize,
-                exitingImmersiveTask = exitingImmersiveTask,
+                exitingImmersiveTask = exitImmersiveResult.asExit()?.exitingTask,
             )
             taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
+            exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
             return t
         }
         if (taskIdToMinimize == null) {
             val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition)
             val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
             remoteTransitionHandler.setTransition(t)
+            exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
             return t
         }
         val remoteTransitionHandler =
@@ -704,6 +687,7 @@
         val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
         remoteTransitionHandler.setTransition(t)
         taskIdToMinimize.let { addPendingMinimizeTransition(t, it) }
+        exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
         return t
     }
 
@@ -794,6 +778,10 @@
         resizeTrigger: ResizeTrigger,
         motionEvent: MotionEvent?,
     ) {
+        desktopModeEventLogger.logTaskResizingStarted(
+            resizeTrigger, motionEvent, taskInfo, displayController
+        )
+
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
 
         val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
@@ -872,9 +860,6 @@
             return
         }
 
-        desktopModeEventLogger.logTaskResizingStarted(
-            ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent, taskInfo, displayController
-        )
         toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
     }
 
@@ -962,13 +947,17 @@
      */
     fun snapToHalfScreen(
         taskInfo: RunningTaskInfo,
-        taskSurface: SurfaceControl,
+        taskSurface: SurfaceControl?,
         currentDragBounds: Rect,
         position: SnapPosition,
         resizeTrigger: ResizeTrigger,
         motionEvent: MotionEvent?,
         desktopWindowDecoration: DesktopModeWindowDecoration,
     ) {
+        desktopModeEventLogger.logTaskResizingStarted(
+            resizeTrigger, motionEvent, taskInfo, displayController
+        )
+
         if (DesktopModeFlags.ENABLE_TILE_RESIZING.isTrue()) {
             val isTiled = desktopTilingDecorViewModel.snapToHalfScreen(
                 taskInfo,
@@ -994,7 +983,7 @@
             // Handle the case where we attempt to snap resize when already snap resized: the task
             // position won't need to change but we want to animate the surface going back to the
             // snapped position from the "dragged-to-the-edge" position.
-            if (destinationBounds != currentDragBounds) {
+            if (destinationBounds != currentDragBounds && taskSurface != null) {
                 returnToDragStartAnimator.start(
                     taskInfo.taskId,
                     taskSurface,
@@ -1011,8 +1000,40 @@
         toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds)
     }
 
+    /**
+     * Handles snap resizing a [taskInfo] to [position] instantaneously, for example when the
+     * [resizeTrigger] is the snap resize menu using any [motionEvent] or a keyboard shortcut.
+     */
+    fun handleInstantSnapResizingTask(
+        taskInfo: RunningTaskInfo,
+        position: SnapPosition,
+        resizeTrigger: ResizeTrigger,
+        motionEvent: MotionEvent? = null,
+        desktopModeWindowDecoration: DesktopModeWindowDecoration,
+    ) {
+        if (!isSnapResizingAllowed(taskInfo)) {
+            Toast.makeText(
+                getContext(),
+                R.string.desktop_mode_non_resizable_snap_text,
+                Toast.LENGTH_SHORT
+            ).show()
+            return
+        }
+
+        snapToHalfScreen(
+            taskInfo,
+            null,
+            taskInfo.configuration.windowConfiguration.bounds,
+            position,
+            resizeTrigger,
+            motionEvent,
+            desktopModeWindowDecoration
+        )
+    }
+
+
     @VisibleForTesting
-    fun handleSnapResizingTask(
+    fun handleSnapResizingTaskOnDrag(
         taskInfo: RunningTaskInfo,
         position: SnapPosition,
         taskSurface: SurfaceControl,
@@ -1022,7 +1043,7 @@
         desktopModeWindowDecoration: DesktopModeWindowDecoration,
     ) {
         releaseVisualIndicator()
-        if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
+        if (!isSnapResizingAllowed(taskInfo)) {
             interactionJankMonitor.begin(
                 taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable"
             )
@@ -1047,9 +1068,6 @@
             } else {
                 ResizeTrigger.DRAG_RIGHT
             }
-            desktopModeEventLogger.logTaskResizingStarted(
-                resizeTrigger, motionEvent, taskInfo, displayController
-            )
             interactionJankMonitor.begin(
                 taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
             )
@@ -1065,6 +1083,9 @@
         }
     }
 
+    private fun isSnapResizingAllowed(taskInfo: RunningTaskInfo) =
+        taskInfo.isResizeable || !DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()
+
     private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect {
         val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return Rect()
 
@@ -1179,7 +1200,7 @@
         val userContext =
             context.createContextAsUser(userHandle, /* flags= */ 0)
         val intent = Intent(userContext, DesktopWallpaperActivity::class.java)
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId)
         val options =
             ActivityOptions.makeBasic().apply {
                 launchWindowingMode = WINDOWING_MODE_FULLSCREEN
@@ -1472,10 +1493,14 @@
                 )
             }
             WINDOWING_MODE_FREEFORM -> {
-                // TODO(b/336289597): This currently does not respect the desktop window limit.
                 val wct = WindowContainerTransaction()
                 wct.sendPendingIntent(launchIntent, fillIn, options.toBundle())
-                transitions.startTransition(TRANSIT_OPEN, wct, null)
+                startLaunchTransition(
+                    transitionType = TRANSIT_OPEN,
+                    wct = wct,
+                    launchingTaskId = null,
+                    displayId = callingTaskInfo.displayId
+                )
             }
         }
     }
@@ -1832,26 +1857,12 @@
         getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) }
     }
 
-    /** Move the focused desktop task in given `displayId` to next display. */
-    fun moveFocusedTaskToNextDisplay(displayId: Int) {
-        getFocusedFreeformTask(displayId)?.let { moveToNextDisplay(it.taskId) }
-    }
-
     private fun getFocusedFreeformTask(displayId: Int): RunningTaskInfo? {
         return shellTaskOrganizer.getRunningTasks(displayId).find { taskInfo ->
             taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
         }
     }
 
-    // TODO(b/364154795): wait for the completion of moveToNextDisplay transition, otherwise it will
-    //  pick a wrong task when a user quickly perform other actions with keyboard shortcuts after
-    //  moveToNextDisplay.
-    private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? =
-        shellTaskOrganizer.getRunningTasks().find { taskInfo ->
-            taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
-                    focusTransitionObserver.hasGlobalFocus(taskInfo)
-        }
-
     /**
      * Requests a task be transitioned from desktop to split select. Applies needed windowing
      * changes if this transition is enabled.
@@ -1993,7 +2004,7 @@
                 }
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.LEFT,
                     taskSurface,
@@ -2004,7 +2015,7 @@
                 )
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.RIGHT,
                     taskSurface,
@@ -2253,31 +2264,6 @@
         taskRepository.dump(pw, innerPrefix)
     }
 
-    override fun handleKeyGestureEvent(
-        event: KeyGestureEvent,
-        focusedToken: IBinder?
-    ): Boolean {
-        if (!isKeyGestureSupported(event.keyGestureType)) return false
-        when (event.keyGestureType) {
-            KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
-                if (event.keycodes.contains(KeyEvent.KEYCODE_D) &&
-                    event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)) {
-                    logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
-                    getGloballyFocusedFreeformTask()?.let { moveToNextDisplay(it.taskId) }
-                    return true
-                }
-                return false
-            }
-            else -> return false
-        }
-    }
-
-    override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) {
-        KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY
-            -> enableMoveToNextDisplayShortcut()
-        else -> false
-    }
-
     /** The interface for calls from outside the shell, within the host process. */
     @ExternalThread
     private inner class DesktopModeImpl : DesktopMode {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index e848b88..2ae9828 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -254,8 +254,13 @@
         finishT.hide(sc);
         final Rect startBounds = new Rect(change.getStartAbsBounds());
         animator.addUpdateListener(animation -> {
-            t.setPosition(sc, startBounds.left,
-                    startBounds.top + (animation.getAnimatedFraction() * screenHeight));
+            final float newTop = startBounds.top + (animation.getAnimatedFraction() * screenHeight);
+            t.setPosition(sc, startBounds.left, newTop);
+            if (newTop > screenHeight) {
+                // At this point the task surface is off-screen, so hide it to prevent flicker
+                // failures. See b/377651666.
+                t.hide(sc);
+            }
             t.apply();
         });
         animator.addListener(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index b618bf1..319bfac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -42,6 +42,7 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
@@ -54,6 +55,7 @@
 
 import com.android.internal.protolog.ProtoLog;
 import com.android.window.flags.Flags;
+import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -80,6 +82,8 @@
 
     private final Transitions mTransitions;
     private final ShellController mShellController;
+
+    private final DisplayController mDisplayController;
     private final Handler mMainHandler;
     private final ShellExecutor mMainExecutor;
 
@@ -121,12 +125,14 @@
     public KeyguardTransitionHandler(
             @NonNull ShellInit shellInit,
             @NonNull ShellController shellController,
+            @NonNull DisplayController displayController,
             @NonNull Transitions transitions,
             @NonNull TaskStackListenerImpl taskStackListener,
             @NonNull Handler mainHandler,
             @NonNull ShellExecutor mainExecutor) {
         mTransitions = transitions;
         mShellController = shellController;
+        mDisplayController = displayController;
         mMainHandler = mainHandler;
         mMainExecutor = mainExecutor;
         mTaskStackListener = taskStackListener;
@@ -429,10 +435,10 @@
         @Override
         public void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
-            final KeyguardState keyguardState =
-                    new KeyguardState.Builder(android.view.Display.DEFAULT_DISPLAY)
-                            .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build();
-            wct.addKeyguardState(keyguardState);
+            for (Display display : mDisplayController.getDisplays()) {
+                wct.addKeyguardState(new KeyguardState.Builder(display.getDisplayId())
+                        .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build());
+            }
             mMainExecutor.execute(() -> {
                 mTransitions.startTransition(keyguardShowing ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK,
                         wct, KeyguardTransitionHandler.this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 5ffc64f..79a9ce5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -47,7 +47,6 @@
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipMenuController;
-import com.android.wm.shell.common.split.SplitScreenUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.DefaultMixedHandler;
@@ -312,10 +311,10 @@
     }
 
     /** Whether a particular package is same as current pip package. */
-    public boolean isPackageActiveInPip(String packageName) {
-        final TaskInfo inPipTask = mPipOrganizer.getTaskInfo();
-        return packageName != null && inPipTask != null && mPipOrganizer.isInPip()
-                && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent));
+    public boolean isPackageActiveInPip(@Nullable String packageName) {
+        return packageName != null
+                && mPipBoundsState.getLastPipComponentName() != null
+                && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName());
     }
 
     /** Add PiP-related changes to `outWCT` for the given request. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
index eb33ff4..35c90ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
@@ -52,6 +52,9 @@
     private final SurfaceControl.Transaction mStartTransaction;
     private final SurfaceControl.Transaction mFinishTransaction;
 
+    private final int mCornerRadius;
+    private final int mShadowRadius;
+
     // Bounds updated by the evaluator as animator is running.
     private final Rect mAnimatedRect = new Rect();
 
@@ -128,6 +131,8 @@
 
         final int enterAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
+        mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+        mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
         setDuration(enterAnimationDuration);
         setFloatValues(0f, 1f);
         setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
@@ -177,6 +182,8 @@
         mTransformTensor.postRotate(degrees);
         tx.setMatrix(mLeash, mTransformTensor, mMatrixTmp);
 
+        tx.setCornerRadius(mLeash, mCornerRadius).setShadowRadius(mLeash, mShadowRadius);
+
         if (mContentOverlay != null) {
             mContentOverlay.onAnimationUpdate(tx, 1f / scaleX, fraction, mEndBounds);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
index 4558a9f..06e8349 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
@@ -29,6 +29,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
 import com.android.wm.shell.shared.animation.Interpolators;
 
@@ -50,6 +51,9 @@
     private Runnable mAnimationEndCallback;
     private RectEvaluator mRectEvaluator;
 
+    private final int mCornerRadius;
+    private final int mShadowRadius;
+
     // Bounds relative to which scaling/cropping must be done.
     private final Rect mBaseBounds = new Rect();
 
@@ -74,7 +78,8 @@
                 mAnimationStartCallback.run();
             }
             if (mStartTx != null) {
-                setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta);
+                setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta,
+                        mCornerRadius, mShadowRadius);
                 mStartTx.apply();
             }
         }
@@ -83,7 +88,8 @@
         public void onAnimationEnd(Animator animation) {
             super.onAnimationEnd(animation);
             if (mFinishTx != null) {
-                setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f);
+                setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f,
+                        mCornerRadius, mShadowRadius);
             }
             if (mAnimationEndCallback != null) {
                 mAnimationEndCallback.run();
@@ -99,7 +105,8 @@
                             mSurfaceControlTransactionFactory.getTransaction();
                     final float fraction = getAnimatedFraction();
                     final float degrees = (1.0f - fraction) * mDelta;
-                    setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees);
+                    setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees,
+                            mCornerRadius, mShadowRadius);
                     tx.apply();
                 }
             };
@@ -128,6 +135,9 @@
 
         mRectEvaluator = new RectEvaluator(mAnimatedRect);
 
+        mCornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+        mShadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+
         setObjectValues(startBounds, endBounds);
         setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         addListener(mAnimatorListener);
@@ -152,7 +162,7 @@
      * @param degrees degrees of rotation - counter-clockwise is positive by convention.
      */
     private static void setBoundsAndRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
-            Rect baseBounds, Rect targetBounds, float degrees) {
+            Rect baseBounds, Rect targetBounds, float degrees, int cornerRadius, int shadowRadius) {
         Matrix transformTensor = new Matrix();
         final float[] mMatrixTmp = new float[9];
         final float scaleX = (float) targetBounds.width() / baseBounds.width();
@@ -162,7 +172,9 @@
         transformTensor.postTranslate(targetBounds.left, targetBounds.top);
         transformTensor.postRotate(degrees, targetBounds.centerX(), targetBounds.centerY());
 
-        tx.setMatrix(leash, transformTensor, mMatrixTmp);
+        tx.setMatrix(leash, transformTensor, mMatrixTmp)
+                .setCornerRadius(leash, cornerRadius)
+                .setShadowRadius(leash, shadowRadius);
     }
 
     @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index e901c39..6d2df95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.pip2.phone;
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 
@@ -293,6 +294,11 @@
 
         // Update the display layout caches even if we are not in PiP.
         setDisplayLayout(mDisplayController.getDisplayLayout(displayId));
+        if (toRotation != ROTATION_UNDEFINED) {
+            // Make sure we rotate to final rotation ourselves in case display change is coming
+            // from the remote rotation as a part of an already collecting transition.
+            mPipDisplayLayoutState.rotateTo(toRotation);
+        }
 
         if (!mPipTransitionState.isInPip()) {
             // Skip the PiP-relevant updates if we aren't in a valid PiP state.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 3738353..fd387d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -785,8 +785,16 @@
 
     private void handleFlingTransition(SurfaceControl.Transaction startTx,
             SurfaceControl.Transaction finishTx, Rect destinationBounds) {
-        startTx.setPosition(mPipTransitionState.getPinnedTaskLeash(),
-                destinationBounds.left, destinationBounds.top);
+        SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash();
+        int cornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+        int shadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+
+        // merge transactions so everything is done on startTx
+        startTx.merge(finishTx);
+
+        startTx.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
+                .setCornerRadius(pipLeash, cornerRadius)
+                .setShadowRadius(pipLeash, shadowRadius);
         startTx.apply();
 
         // All motion operations have actually finished, so make bounds cache updates.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 02f5955..08e6727 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -241,7 +241,7 @@
             extra.putParcelable(PIP_TASK_LEASH, pipChange.getLeash());
             mPipTransitionState.setState(PipTransitionState.ENTERING_PIP, extra);
 
-            if (mPipTransitionState.isInSwipePipToHomeTransition()) {
+            if (isInSwipePipToHomeTransition()) {
                 // If this is the second transition as a part of swipe PiP to home cuj,
                 // handle this transition as a special case with no-op animation.
                 return handleSwipePipToHomeTransition(info, startTransaction, finishTransaction,
@@ -420,7 +420,8 @@
         }
 
         // Update the src-rect-hint in params in place, to set up initial animator transform.
-        params.getSourceRectHint().set(adjustedSourceRectHint);
+        params.copyOnlySet(new PictureInPictureParams.Builder()
+                .setSourceRectHint(adjustedSourceRectHint).build());
 
         // Config-at-end transitions need to have their activities transformed before starting
         // the animation; this makes the buffer seem like it's been updated to final size.
@@ -701,6 +702,13 @@
             @NonNull TransitionInfo.Change pipChange) {
         TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
         int startRotation = pipChange.getStartRotation();
+        if (pipChange.getEndRotation() != ROTATION_UNDEFINED
+                && startRotation != pipChange.getEndRotation()) {
+            // If PiP change was collected along with the display change and the orientation change
+            // happened in sync with the PiP change, then do not treat this as fixed-rotation case.
+            return ROTATION_0;
+        }
+
         int endRotation = fixedRotationChange != null
                 ? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation();
         int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 49cf8ae..35e6c8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -46,6 +46,8 @@
             "ShellBackPreview"),
     WM_SHELL_RECENT_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_SHELL),
+    WM_SHELL_TASK_OBSERVER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+            Consts.TAG_WM_SHELL),
     // TODO(b/282232877): turn logToLogcat to false.
     WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
index b58f068..68dc0f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -45,9 +45,15 @@
      */
     void onRunningTaskChanged(in RunningTaskInfo taskInfo);
 
-    /** A task has moved to front. */
-    void onTaskMovedToFront(in GroupedTaskInfo[] visibleTasks);
+    /** A task has moved to front. Only used if enableShellTopTaskTracking() is disabled. */
+    void onTaskMovedToFront(in GroupedTaskInfo taskToFront);
 
-    /** A task info has changed. */
+    /** A task info has changed. Only used if enableShellTopTaskTracking() is disabled. */
     void onTaskInfoChanged(in RunningTaskInfo taskInfo);
+
+    /**
+     * If enableShellTopTaskTracking() is enabled, this reports the set of all visible tasks.
+     * Otherwise, this reports only the new top most visible task.
+     */
+    void onVisibleTasksChanged(in GroupedTaskInfo[] visibleTasks);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 9911669..6da4f51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -17,14 +17,18 @@
 package com.android.wm.shell.recents;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PC;
 
+import static com.android.wm.shell.Flags.enableShellTopTaskTracking;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER;
 import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
 
 import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.app.IApplicationThread;
 import android.app.KeyguardManager;
@@ -65,7 +69,6 @@
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -111,6 +114,11 @@
     private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
 
     /**
+     * Cached list of the visible tasks, sorted from top most to bottom most.
+     */
+    private final List<RunningTaskInfo> mVisibleTasks = new ArrayList<>();
+
+    /**
      * Creates {@link RecentTasksController}, returns {@code null} if the feature is not
      * supported.
      */
@@ -170,10 +178,8 @@
         mShellCommandHandler.addDumpCallback(this::dump, this);
         mTaskStackListener.addListener(this);
         mDesktopRepository.ifPresent(it -> it.addActiveTaskListener(this));
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
-                    mMainExecutor);
-        }
+        mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
+                mMainExecutor);
         mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
                 mMainExecutor, isKeyguardLocked -> notifyRecentTasksChanged());
     }
@@ -205,7 +211,7 @@
         mTaskSplitBoundsMap.put(taskId1, splitBounds);
         mTaskSplitBoundsMap.put(taskId2, splitBounds);
         notifyRecentTasksChanged();
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Add split pair: %d, %d, %s",
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Add split pair: %d, %d, %s",
                 taskId1, taskId2, splitBounds);
         return true;
     }
@@ -221,7 +227,7 @@
             mTaskSplitBoundsMap.remove(taskId);
             mTaskSplitBoundsMap.remove(pairedTaskId);
             notifyRecentTasksChanged();
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Remove split pair: %d, %d",
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Remove split pair: %d, %d",
                     taskId, pairedTaskId);
         }
     }
@@ -234,7 +240,17 @@
 
         // We could do extra verification of requiring both taskIds of a pair and verifying that
         // the same split bounds object is returned... but meh. Seems unnecessary.
-        return mTaskSplitBoundsMap.get(taskId);
+        SplitBounds splitBounds = mTaskSplitBoundsMap.get(taskId);
+        if (splitBounds != null) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "getSplitBoundsForTaskId: taskId=%d splitBoundsTasks=[%d, %d]", taskId,
+                    splitBounds.leftTopTaskId, splitBounds.rightBottomTaskId);
+        } else {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "getSplitBoundsForTaskId: expected split bounds for taskId=%d but not found",
+                    taskId);
+        }
+        return splitBounds;
     }
 
     @Override
@@ -249,7 +265,10 @@
 
     @Override
     public void onTaskStackChanged() {
-        notifyRecentTasksChanged();
+        if (!enableShellTopTaskTracking()) {
+            // Skip notifying recent tasks changed whenever task stack changes
+            notifyRecentTasksChanged();
+        }
     }
 
     @Override
@@ -263,15 +282,18 @@
         notifyRecentTasksChanged();
     }
 
-    public void onTaskAdded(ActivityManager.RunningTaskInfo taskInfo) {
+    public void onTaskAdded(RunningTaskInfo taskInfo) {
         notifyRunningTaskAppeared(taskInfo);
     }
 
-    public void onTaskRemoved(ActivityManager.RunningTaskInfo taskInfo) {
+    public void onTaskRemoved(RunningTaskInfo taskInfo) {
         // Remove any split pairs associated with this task
         removeSplitPair(taskInfo.taskId);
-        notifyRecentTasksChanged();
         notifyRunningTaskVanished(taskInfo);
+        if (!enableShellTopTaskTracking()) {
+            // Only notify recent tasks changed if we aren't already notifying the visible tasks
+            notifyRecentTasksChanged();
+        }
     }
 
     /**
@@ -279,7 +301,7 @@
      *
      * This currently includes windowing mode and visibility.
      */
-    public void onTaskRunningInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+    public void onTaskRunningInfoChanged(RunningTaskInfo taskInfo) {
         notifyRecentTasksChanged();
         notifyRunningTaskChanged(taskInfo);
     }
@@ -290,14 +312,21 @@
     }
 
     @Override
+    public void onTaskMovedToFrontThroughTransition(RunningTaskInfo runningTaskInfo) {
+        notifyTaskMovedToFront(runningTaskInfo);
+    }
+
+    @Override
     public void onTaskChangedThroughTransition(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
         notifyTaskInfoChanged(taskInfo);
     }
 
     @Override
-    public void onTaskMovedToFrontThroughTransition(
-            ActivityManager.RunningTaskInfo runningTaskInfo) {
-        notifyTaskMovedToFront(runningTaskInfo);
+    public void onVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) {
+        mVisibleTasks.clear();
+        mVisibleTasks.addAll(visibleTasks);
+        // Notify with all the info and not just the running task info
+        notifyVisibleTasksChanged(visibleTasks);
     }
 
     @VisibleForTesting
@@ -316,7 +345,7 @@
     /**
      * Notify the running task listener that a task appeared on desktop environment.
      */
-    private void notifyRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+    private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) {
         if (mListener == null
                 || !shouldEnableRunningTasksForDesktopMode()
                 || taskInfo.realActivity == null) {
@@ -330,9 +359,25 @@
     }
 
     /**
+     * Notify the running task listener that a task was changed on desktop environment.
+     */
+    private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) {
+        if (mListener == null
+                || !shouldEnableRunningTasksForDesktopMode()
+                || taskInfo.realActivity == null) {
+            return;
+        }
+        try {
+            mListener.onRunningTaskChanged(taskInfo);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed call onRunningTaskChanged", e);
+        }
+    }
+
+    /**
      * Notify the running task listener that a task was removed on desktop environment.
      */
-    private void notifyRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+    private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) {
         if (mListener == null
                 || !shouldEnableRunningTasksForDesktopMode()
                 || taskInfo.realActivity == null) {
@@ -346,25 +391,30 @@
     }
 
     /**
-     * Notify the running task listener that a task was changed on desktop environment.
+     * Notify the recents task listener that a task moved to front via a transition.
      */
-    private void notifyRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+    private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
         if (mListener == null
-                || !shouldEnableRunningTasksForDesktopMode()
-                || taskInfo.realActivity == null) {
+                || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
+                || taskInfo.realActivity == null
+                || enableShellTopTaskTracking()) {
             return;
         }
         try {
-            mListener.onRunningTaskChanged(taskInfo);
+            mListener.onTaskMovedToFront(GroupedTaskInfo.forFullscreenTasks(taskInfo));
         } catch (RemoteException e) {
-            Slog.w(TAG, "Failed call onRunningTaskChanged", e);
+            Slog.w(TAG, "Failed call onTaskMovedToFront", e);
         }
     }
 
+    /**
+     * Notify the recents task listener that a task changed via a transition.
+     */
     private void notifyTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
         if (mListener == null
                 || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
-                || taskInfo.realActivity == null) {
+                || taskInfo.realActivity == null
+                || enableShellTopTaskTracking()) {
             return;
         }
         try {
@@ -374,17 +424,21 @@
         }
     }
 
-    private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+    /**
+     * Notifies that the test of visible tasks have changed.
+     */
+    private void notifyVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) {
         if (mListener == null
                 || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue()
-                || taskInfo.realActivity == null) {
+                || !enableShellTopTaskTracking()) {
             return;
         }
         try {
-            GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo);
-            mListener.onTaskMovedToFront(new GroupedTaskInfo[]{ runningTask });
+            // Compute the visible recent tasks in order, and move the task to the top
+            mListener.onVisibleTasksChanged(generateList(visibleTasks)
+                    .toArray(new GroupedTaskInfo[0]));
         } catch (RemoteException e) {
-            Slog.w(TAG, "Failed call onTaskMovedToFront", e);
+            Slog.w(TAG, "Failed call onVisibleTasksChanged", e);
         }
     }
 
@@ -397,6 +451,11 @@
     @VisibleForTesting
     void registerRecentTasksListener(IRecentTasksListener listener) {
         mListener = listener;
+        if (enableShellTopTaskTracking()) {
+            ProtoLog.v(WM_SHELL_TASK_OBSERVER, "registerRecentTasksListener");
+            // Post a notification for the current set of visible tasks
+            mMainExecutor.executeDelayed(() -> notifyVisibleTasksChanged(mVisibleTasks), 0);
+        }
     }
 
     @VisibleForTesting
@@ -411,14 +470,18 @@
 
     @VisibleForTesting
     ArrayList<GroupedTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
-        // Note: the returned task list is from the most-recent to least-recent order
-        final List<RecentTaskInfo> rawList = mActivityTaskManager.getRecentTasks(
-                maxNum, flags, userId);
+        // Note: the returned task list is ordered from the most-recent to least-recent order
+        return generateList(mActivityTaskManager.getRecentTasks(maxNum, flags, userId));
+    }
 
+    /**
+     * Generates a list of GroupedTaskInfos for the given list of tasks.
+     */
+    private <T extends TaskInfo> ArrayList<GroupedTaskInfo> generateList(@NonNull List<T> tasks) {
         // Make a mapping of task id -> task info
         final SparseArray<TaskInfo> rawMapping = new SparseArray<>();
-        for (int i = 0; i < rawList.size(); i++) {
-            final TaskInfo taskInfo = rawList.get(i);
+        for (int i = 0; i < tasks.size(); i++) {
+            final TaskInfo taskInfo = tasks.get(i);
             rawMapping.put(taskInfo.taskId, taskInfo);
         }
 
@@ -427,10 +490,10 @@
 
         int mostRecentFreeformTaskIndex = Integer.MAX_VALUE;
 
+        ArrayList<GroupedTaskInfo> groupedTasks = new ArrayList<>();
         // Pull out the pairs as we iterate back in the list
-        ArrayList<GroupedTaskInfo> recentTasks = new ArrayList<>();
-        for (int i = 0; i < rawList.size(); i++) {
-            final RecentTaskInfo taskInfo = rawList.get(i);
+        for (int i = 0; i < tasks.size(); i++) {
+            final TaskInfo taskInfo = tasks.get(i);
             if (!rawMapping.contains(taskInfo.taskId)) {
                 // If it's not in the mapping, then it was already paired with another task
                 continue;
@@ -441,7 +504,7 @@
                     && mDesktopRepository.get().isActiveTask(taskInfo.taskId)) {
                 // Freeform tasks will be added as a separate entry
                 if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) {
-                    mostRecentFreeformTaskIndex = recentTasks.size();
+                    mostRecentFreeformTaskIndex = groupedTasks.size();
                 }
                 // If task has their app bounds set to null which happens after reboot, set the
                 // app bounds to persisted lastFullscreenBounds. Also set the position in parent
@@ -461,36 +524,34 @@
             }
 
             final int pairedTaskId = mSplitTasks.get(taskInfo.taskId, INVALID_TASK_ID);
-            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
-                    pairedTaskId)) {
+            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
                 final TaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
                 rawMapping.remove(pairedTaskId);
-                recentTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
+                groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
                         mTaskSplitBoundsMap.get(pairedTaskId)));
             } else {
-                recentTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo));
+                // TODO(346588978): Consolidate multiple visible fullscreen tasks into the same
+                //  grouped task
+                groupedTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo));
             }
         }
 
         // Add a special entry for freeform tasks
         if (!freeformTasks.isEmpty()) {
-            recentTasks.add(mostRecentFreeformTaskIndex,
+            groupedTasks.add(mostRecentFreeformTaskIndex,
                     GroupedTaskInfo.forFreeformTasks(
                             freeformTasks,
                             minimizedFreeformTasks));
         }
 
-        return recentTasks;
-    }
+        if (enableShellTopTaskTracking()) {
+            // We don't current send pinned tasks as a part of recent or running tasks, so remove
+            // them from the list here
+            groupedTasks.removeIf(
+                    gti -> gti.getTaskInfo1().getWindowingMode() == WINDOWING_MODE_PINNED);
+        }
 
-    /**
-     * Returns the top running leaf task.
-     */
-    @Nullable
-    public ActivityManager.RunningTaskInfo getTopRunningTask() {
-        List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1,
-                false /* filterOnlyVisibleRecents */);
-        return tasks.isEmpty() ? null : tasks.get(0);
+        return groupedTasks;
     }
 
     /**
@@ -498,12 +559,13 @@
      * NOTE: This path currently makes assumptions that ignoreTaskToken is for the top task.
      */
     @Nullable
-    public ActivityManager.RunningTaskInfo getTopRunningTask(
+    public RunningTaskInfo getTopRunningTask(
             @Nullable WindowContainerToken ignoreTaskToken) {
-        List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(2,
-                false /* filterOnlyVisibleRecents */);
+        final List<RunningTaskInfo> tasks = enableShellTopTaskTracking()
+                ? mVisibleTasks
+                : mActivityTaskManager.getTasks(2, false /* filterOnlyVisibleRecents */);
         for (int i = 0; i < tasks.size(); i++) {
-            final ActivityManager.RunningTaskInfo task = tasks.get(i);
+            final RunningTaskInfo task = tasks.get(i);
             if (task.token.equals(ignoreTaskToken)) {
                 continue;
             }
@@ -541,7 +603,7 @@
     }
 
     /**
-     * Find the background task that match the given taskId.
+     * Find the background task (in the recent tasks list) that matches the given taskId.
      */
     @Nullable
     public RecentTaskInfo findTaskInBackground(int taskId) {
@@ -638,29 +700,34 @@
             }
 
             @Override
-            public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+            public void onRunningTaskAppeared(RunningTaskInfo taskInfo) {
                 mListener.call(l -> l.onRunningTaskAppeared(taskInfo));
             }
 
             @Override
-            public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+            public void onRunningTaskVanished(RunningTaskInfo taskInfo) {
                 mListener.call(l -> l.onRunningTaskVanished(taskInfo));
             }
 
             @Override
-            public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+            public void onRunningTaskChanged(RunningTaskInfo taskInfo) {
                 mListener.call(l -> l.onRunningTaskChanged(taskInfo));
             }
 
             @Override
-            public void onTaskMovedToFront(GroupedTaskInfo[] taskInfo) {
-                mListener.call(l -> l.onTaskMovedToFront(taskInfo));
+            public void onTaskMovedToFront(GroupedTaskInfo taskToFront) {
+                mListener.call(l -> l.onTaskMovedToFront(taskToFront));
             }
 
             @Override
             public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
                 mListener.call(l -> l.onTaskInfoChanged(taskInfo));
             }
+
+            @Override
+            public void onVisibleTasksChanged(GroupedTaskInfo[] visibleTasks) {
+                mListener.call(l -> l.onVisibleTasksChanged(visibleTasks));
+            }
         };
 
         public IRecentTasksImpl(RecentTasksController controller) {
@@ -714,12 +781,12 @@
         }
 
         @Override
-        public ActivityManager.RunningTaskInfo[] getRunningTasks(int maxNum) {
-            final ActivityManager.RunningTaskInfo[][] tasks =
-                    new ActivityManager.RunningTaskInfo[][]{null};
+        public RunningTaskInfo[] getRunningTasks(int maxNum) {
+            final RunningTaskInfo[][] tasks =
+                    new RunningTaskInfo[][]{null};
             executeRemoteCallWithTaskPermission(mController, "getRunningTasks",
                     (controller) -> tasks[0] = ActivityTaskManager.getInstance().getTasks(maxNum)
-                            .toArray(new ActivityManager.RunningTaskInfo[0]),
+                            .toArray(new RunningTaskInfo[0]),
                     true /* blocking */);
             return tasks[0];
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
index d28a462..93f2e4c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -17,37 +17,162 @@
 package com.android.wm.shell.recents
 
 import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
 import android.os.IBinder
 import android.util.ArrayMap
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
 import android.window.DesktopModeFlags
 import android.window.TransitionInfo
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.Flags.enableShellTopTaskTracking
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER
 import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
 import dagger.Lazy
+import java.io.PrintWriter
+import java.util.StringJoiner
 import java.util.concurrent.Executor
 
 /**
- * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners
- * about task stack changes.
+ * A [Transitions.TransitionObserver] that observes shell transitions, tracks the visible tasks
+ * and notifies listeners whenever the visible tasks change (at the start and end of a transition).
  *
- * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it
+ * This can be replaced once we have a generalized task repository tracking visible tasks.
  */
 class TaskStackTransitionObserver(
+    shellInit: ShellInit,
+    private val shellTaskOrganizer: Lazy<ShellTaskOrganizer>,
+    private val shellCommandHandler: ShellCommandHandler,
     private val transitions: Lazy<Transitions>,
-    shellInit: ShellInit
-) : Transitions.TransitionObserver {
+) : Transitions.TransitionObserver, ShellTaskOrganizer.TaskVanishedListener {
+
+    // List of currently visible tasks sorted in z-order from top-most to bottom-most, only used
+    // when Flags.enableShellTopTaskTracking() is enabled.
+    private var visibleTasks: MutableList<RunningTaskInfo> = mutableListOf()
+    private val pendingCloseTasks: MutableList<RunningTaskInfo> = mutableListOf()
+    // Set of listeners to notify when the visible tasks change
     private val taskStackTransitionObserverListeners =
         ArrayMap<TaskStackTransitionObserverListener, Executor>()
+    // Used to filter out leaf-tasks
+    private val leafTaskFilter: TransitionUtil.LeafTaskFilter = TransitionUtil.LeafTaskFilter()
 
     init {
         shellInit.addInitCallback(::onInit, this)
     }
 
     fun onInit() {
+        shellTaskOrganizer.get().addTaskVanishedListener(this)
+        shellCommandHandler.addDumpCallback(::dump, this)
         transitions.get().registerObserver(this)
+
+        // TODO(346588978): We need to update the running tasks once the ShellTaskOrganizer is
+        // registered since there is no existing transition (yet) corresponding for the already
+        // visible tasks
+    }
+
+    /**
+     * This method handles transition ready when only
+     * DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL is set.
+     */
+    private fun onDesktopOnlyFlagTransitionReady(info: TransitionInfo) {
+        for (change in info.changes) {
+            if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
+                continue
+            }
+
+            val taskInfo = change.taskInfo
+            if (taskInfo == null || taskInfo.taskId == -1) {
+                continue
+            }
+
+            // Find the first task that is opening, this should be the one at the front after
+            // the transition
+            if (TransitionUtil.isOpeningType(change.mode)) {
+                notifyOnTaskMovedToFront(taskInfo)
+                break
+            } else if (change.mode == TRANSIT_CHANGE) {
+                notifyOnTaskChanged(taskInfo)
+            }
+        }
+    }
+
+    /**
+     * This method handles transition ready when Flags.enableShellTopTaskTracking() is set.
+     */
+    private fun onShellTopTaskTrackerFlagTransitionReady(info: TransitionInfo) {
+        ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Transition ready: %d", info.debugId)
+
+        // Filter out non-leaf tasks (we will likely need them later, but visible task tracking
+        // is currently used only for visible leaf tasks)
+        val changesReversed = mutableListOf<TransitionInfo.Change>()
+        for (change in info.changes) {
+            if (!leafTaskFilter.test(change)) {
+                // Not a leaf task
+                continue
+            }
+            changesReversed.add(0, change)
+        }
+
+        // We iterate the change list in reverse order because changes are sorted top to bottom and
+        // we want to update the lists such that the top most tasks are inserted at the front last
+        var notifyChanges = false
+        for (change in changesReversed) {
+            val taskInfo = change.taskInfo
+            if (taskInfo == null || taskInfo.taskId == -1) {
+                // Not a valid task
+                continue
+            }
+
+            if (TransitionUtil.isClosingMode(change.mode)) {
+                ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tClosing task=%d", taskInfo.taskId)
+
+                // Closing task's visibilities are not committed until after the transition
+                // completes, so track such tasks so that we can notify on finish
+                if (!pendingCloseTasks.any { it.taskId == taskInfo.taskId }) {
+                    pendingCloseTasks.add(taskInfo)
+                }
+            } else if (TransitionUtil.isOpeningMode(change.mode)
+                    || TransitionUtil.isOrderOnly(change)) {
+                ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tOpening task=%d", taskInfo.taskId)
+
+                // Remove from pending close tasks list if it's being opened again
+                pendingCloseTasks.removeIf { it.taskId == taskInfo.taskId }
+                // Move the task to the front of the visible tasks list
+                visibleTasks.removeIf { it.taskId == taskInfo.taskId }
+                visibleTasks.add(0, taskInfo)
+                notifyChanges = true
+            }
+        }
+
+        // TODO(346588978): We should verify the task list has actually changed before notifying
+        //  (ie. starting an activity that's already top-most would result in no visible change)
+        if (notifyChanges) {
+            updateVisibleTasksList("transition-start")
+        }
+    }
+
+    private fun updateVisibleTasksList(reason: String) {
+        // This simply constructs a list of visible tasks, where the always-on-top tasks are moved
+        // to the front of the list in-order, to ensure that they match the visible z order
+        val orderedVisibleTasks = mutableListOf<RunningTaskInfo>()
+        var numAlwaysOnTop = 0
+        for (info in visibleTasks) {
+            if (info.windowingMode == WINDOWING_MODE_PINNED
+                    || info.configuration.windowConfiguration.isAlwaysOnTop) {
+                orderedVisibleTasks.add(numAlwaysOnTop, info)
+                numAlwaysOnTop++
+            } else {
+                orderedVisibleTasks.add(info)
+            }
+        }
+        visibleTasks = orderedVisibleTasks
+
+        dumpVisibleTasks(reason)
+        notifyVisibleTasksChanged(visibleTasks)
     }
 
     override fun onTransitionReady(
@@ -56,26 +181,10 @@
         startTransaction: SurfaceControl.Transaction,
         finishTransaction: SurfaceControl.Transaction
     ) {
-        if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
-            for (change in info.changes) {
-                if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
-                    continue
-                }
-
-                val taskInfo = change.taskInfo
-                if (taskInfo == null || taskInfo.taskId == -1) {
-                    continue
-                }
-
-                // Find the first task that is opening, this should be the one at the front after
-                // the transition
-                if (TransitionUtil.isOpeningType(change.mode)) {
-                    notifyOnTaskMovedToFront(taskInfo)
-                    break
-                } else if (change.mode == TRANSIT_CHANGE) {
-                    notifyOnTaskChanged(taskInfo)
-                }
-            }
+        if (enableShellTopTaskTracking()) {
+            onShellTopTaskTrackerFlagTransitionReady(info)
+        } else if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) {
+            onDesktopOnlyFlagTransitionReady(info)
         }
     }
 
@@ -83,8 +192,35 @@
 
     override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
 
-    override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {}
+    override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
+        if (enableShellTopTaskTracking()) {
+            if (pendingCloseTasks.isNotEmpty()) {
+                // Update the visible task list based on the pending close tasks
+                for (change in pendingCloseTasks) {
+                    visibleTasks.removeIf {
+                        it.taskId == change.taskId
+                    }
+                }
+                updateVisibleTasksList("transition-finished")
+            }
+        }
+    }
 
+    override fun onTaskVanished(taskInfo: RunningTaskInfo?) {
+        if (!enableShellTopTaskTracking()) {
+            return
+        }
+        ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Task vanished: task=%d", taskInfo?.taskId)
+        pendingCloseTasks.removeIf { it.taskId == taskInfo?.taskId }
+        if (visibleTasks.any { it.taskId == taskInfo?.taskId }) {
+            visibleTasks.removeIf { it.taskId == taskInfo?.taskId }
+            updateVisibleTasksList("task-vanished")
+        }
+    }
+
+    /**
+     * Adds a new task stack observer.
+     */
     fun addTaskStackTransitionObserverListener(
         taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
         executor: Executor
@@ -92,6 +228,9 @@
         taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor
     }
 
+    /**
+     * Removes an existing task stack observer.
+     */
     fun removeTaskStackTransitionObserverListener(
         taskStackTransitionObserverListener: TaskStackTransitionObserverListener
     ) {
@@ -99,22 +238,66 @@
     }
 
     private fun notifyOnTaskMovedToFront(taskInfo: RunningTaskInfo) {
+        if (enableShellTopTaskTracking()) {
+            return
+        }
         taskStackTransitionObserverListeners.forEach { (listener, executor) ->
             executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) }
         }
     }
 
     private fun notifyOnTaskChanged(taskInfo: RunningTaskInfo) {
+        if (enableShellTopTaskTracking()) {
+            return
+        }
         taskStackTransitionObserverListeners.forEach { (listener, executor) ->
             executor.execute { listener.onTaskChangedThroughTransition(taskInfo) }
         }
     }
 
+    private fun notifyVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {
+        taskStackTransitionObserverListeners.forEach { (listener, executor) ->
+            executor.execute { listener.onVisibleTasksChanged(visibleTasks) }
+        }
+    }
+
+    fun dump(pw: PrintWriter, prefix: String) {
+        pw.println("${prefix}$TAG:")
+
+        if (visibleTasks.isEmpty()) {
+            pw.println("$prefix  visibleTasks=[]")
+        } else {
+            val stringJoiner = StringJoiner(",\n\t", "[\n\t", "\n]")
+            visibleTasks.forEach {
+                stringJoiner.add("id=${it.taskId} cmp=${it.baseIntent.component}")
+            }
+            pw.println("$prefix  visibleTasks=$stringJoiner")
+        }
+    }
+
+    /** Dumps the set of visible tasks to protolog */
+    private fun dumpVisibleTasks(reason: String) {
+        if (!WM_SHELL_TASK_OBSERVER.isEnabled) {
+            return
+        }
+        ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tVisible tasks (%s)", reason)
+        for (task in visibleTasks) {
+            ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\t\ttaskId=%d package=%s", task.taskId,
+                task.baseIntent.component?.packageName)
+        }
+    }
+
     /** Listener to use to get updates regarding task stack from this observer */
     interface TaskStackTransitionObserverListener {
         /** Called when a task is moved to front. */
         fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
+        /** Called when the set of visible tasks have changed. */
+        fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {}
         /** Called when a task info has changed. */
         fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {}
     }
+
+    companion object {
+        const val TAG = "TaskStackTransitionObserver"
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index cc0e1df..81b96cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -55,7 +55,6 @@
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER;
-import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
@@ -1099,16 +1098,11 @@
 
     void setSideStagePosition(@SplitPosition int sideStagePosition,
             @Nullable WindowContainerTransaction wct) {
-        setSideStagePosition(sideStagePosition, true /* updateBounds */, wct);
-    }
-
-    private void setSideStagePosition(@SplitPosition int sideStagePosition, boolean updateBounds,
-            @Nullable WindowContainerTransaction wct) {
         if (mSideStagePosition == sideStagePosition) return;
         mSideStagePosition = sideStagePosition;
         sendOnStagePositionChanged();
 
-        if (mSideStage.mVisible && updateBounds) {
+        if (mSideStage.mVisible) {
             if (wct == null) {
                 // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
                 onLayoutSizeChanged(mSplitLayout);
@@ -1275,6 +1269,8 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         prepareExitSplitScreen(stage, wct);
         mSplitTransitions.startDismissTransition(wct, this, stage, exitReason);
+        // reset stages to their default sides.
+        setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null);
         logExit(exitReason);
     }
 
@@ -1362,7 +1358,11 @@
     }
 
     void clearSplitPairedInRecents(@ExitReason int exitReason) {
-        if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
+        if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: skipping reason=%s",
+                    !mShouldUpdateRecents ? "shouldn't update" : exitReasonToString(exitReason));
+            return;
+        }
 
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: reason=%s",
                 exitReasonToString(exitReason));
@@ -1598,6 +1598,13 @@
         }
         if (present) {
             updateRecentTasksSplitPair();
+        } else if (mMainStage.getChildCount() == 0 && mSideStage.getChildCount() == 0) {
+            mRecentTasks.ifPresent(recentTasks -> {
+                // remove the split pair mapping from recentTasks, and disable further updates
+                // to splits in the recents until we enter split again.
+                recentTasks.removeSplitPair(taskId);
+            });
+            dismissSplitScreen(-1, EXIT_REASON_ROOT_TASK_VANISHED);
         }
 
         for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -1608,6 +1615,8 @@
     private void updateRecentTasksSplitPair() {
         // Preventing from single task update while processing recents.
         if (!mShouldUpdateRecents || !mPausingTasks.isEmpty()) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateRecentTasksSplitPair: skipping reason=%s",
+                    !mShouldUpdateRecents ? "shouldn't update" : "no pausing tasks");
             return;
         }
         mRecentTasks.ifPresent(recentTasks -> {
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 d71e61a..f89b0d1 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
@@ -78,7 +78,6 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.widget.Toast;
 import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
@@ -572,9 +571,6 @@
         if (decoration == null) {
             return;
         }
-        mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
-                decoration.mTaskInfo,
-                mDisplayController, /* displayLayoutSize= */ null);
         mInteractionJankMonitor.begin(
                 decoration.mTaskSurface, mContext, mMainHandler,
                 Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
@@ -593,33 +589,20 @@
         decoration.closeMaximizeMenu();
     }
 
-    private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) {
+    public void onSnapResize(int taskId, boolean left, @Nullable MotionEvent motionEvent) {
         final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
         if (decoration == null) {
             return;
         }
 
-        if (!decoration.mTaskInfo.isResizeable
-                && DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) {
-            Toast.makeText(mContext,
-                    R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show();
-        } else {
-            ResizeTrigger resizeTrigger =
-                    left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU;
-            mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent,
-                    decoration.mTaskInfo,
-                    mDisplayController, /* displayLayoutSize= */ null);
-            mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
-                    Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
-            mDesktopTasksController.snapToHalfScreen(
-                    decoration.mTaskInfo,
-                    decoration.mTaskSurface,
-                    decoration.mTaskInfo.configuration.windowConfiguration.getBounds(),
-                    left ? SnapPosition.LEFT : SnapPosition.RIGHT,
-                    resizeTrigger,
-                    motionEvent,
-                    mWindowDecorByTaskId.get(taskId));
-        }
+        mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler,
+                Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable");
+        mDesktopTasksController.handleInstantSnapResizingTask(
+                decoration.mTaskInfo,
+                left ? SnapPosition.LEFT : SnapPosition.RIGHT,
+                left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU,
+                motionEvent,
+                decoration);
 
         decoration.closeHandleMenu();
         decoration.closeMaximizeMenu();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index cdcf14e..723bbd3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -81,7 +81,6 @@
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.IconProvider;
 import com.android.window.flags.Flags;
@@ -207,7 +206,7 @@
     private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
     private final DesktopRepository mDesktopRepository;
 
-    DesktopModeWindowDecoration(
+    public DesktopModeWindowDecoration(
             Context context,
             @NonNull Context userContext,
             DisplayController displayController,
@@ -1008,8 +1007,10 @@
         relayoutParams.mWindowDecorConfig = windowDecorConfig;
 
         if (DesktopModeStatus.useRoundedCorners()) {
-            relayoutParams.mCornerRadius =
-                    (int) ScreenDecorationsUtils.getWindowCornerRadius(context);
+            relayoutParams.mCornerRadius = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+                    ? loadDimensionPixelSize(context.getResources(),
+                    R.dimen.desktop_windowing_freeform_rounded_corner_radius)
+                    : INVALID_CORNER_RADIUS;
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 54c247b..62be2c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -238,8 +238,12 @@
         val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds
         updateGlobalMenuPosition(taskBounds, captionX, captionY)
         if (layoutResId == R.layout.desktop_mode_app_header) {
-            // Align the handle menu to the left side of the caption.
-            menuX = marginMenuStart
+            // Align the handle menu to the start of the header.
+            menuX = if (context.isRtl()) {
+                taskBounds.width() - menuWidth - marginMenuStart
+            } else {
+                marginMenuStart
+            }
             menuY = captionY + marginMenuTop
         } else {
             if (DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) {
@@ -261,10 +265,17 @@
         val nonFreeformX = captionX + (captionWidth / 2) - (menuWidth / 2)
         when {
             taskInfo.isFreeform -> {
-                globalMenuPosition.set(
-                    /* x = */ taskBounds.left + marginMenuStart,
-                    /* y = */ taskBounds.top + captionY + marginMenuTop
-                )
+                if (context.isRtl()) {
+                    globalMenuPosition.set(
+                        /* x= */ taskBounds.right - menuWidth - marginMenuStart,
+                        /* y= */ taskBounds.top + captionY + marginMenuTop
+                    )
+                } else {
+                    globalMenuPosition.set(
+                        /* x= */ taskBounds.left + marginMenuStart,
+                        /* y= */ taskBounds.top + captionY + marginMenuTop
+                    )
+                }
             }
             taskInfo.isFullscreen -> {
                 globalMenuPosition.set(
@@ -430,6 +441,9 @@
         return context.resources.getDimensionPixelSize(resourceId)
     }
 
+    private fun Context.isRtl() =
+        resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
     fun close() {
         handleMenuView?.animateCloseMenu {
             handleMenuViewContainer?.releaseView()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index a3c75bf..852eee5f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -107,6 +107,11 @@
     static final int INPUT_SINK_Z_ORDER = -2;
 
     /**
+     * Invalid corner radius that signifies that corner radius should not be set.
+     */
+    static final int INVALID_CORNER_RADIUS = -1;
+
+    /**
      * System-wide context. Only used to create context with overridden configurations.
      */
     final Context mContext;
@@ -449,20 +454,22 @@
             startT.show(mTaskSurface);
         }
 
-        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-            if (!DesktopModeStatus.isVeiledResizeEnabled()) {
-                // When fluid resize is enabled, add a background to freeform tasks
-                int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
-                mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
-                mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
-                mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
-                startT.setColor(mTaskSurface, mTmpColor);
-            }
-            startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
-            finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+                && !DesktopModeStatus.isVeiledResizeEnabled()) {
+            // When fluid resize is enabled, add a background to freeform tasks
+            int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
+            mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
+            mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
+            mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
+            startT.setColor(mTaskSurface, mTmpColor);
         } else if (!DesktopModeStatus.isVeiledResizeEnabled()) {
             startT.unsetColor(mTaskSurface);
         }
+
+        if (params.mCornerRadius != INVALID_CORNER_RADIUS) {
+            startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+            finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+        }
     }
 
     /**
@@ -593,13 +600,25 @@
 
     private Rect calculateBoundingRectLocal(@NonNull OccludingCaptionElement element,
             int elementWidthPx, @NonNull Rect captionRect) {
+        final boolean isRtl =
+                mDecorWindowContext.getResources().getConfiguration().getLayoutDirection()
+                        == View.LAYOUT_DIRECTION_RTL;
         switch (element.mAlignment) {
             case START -> {
-                return new Rect(0, 0, elementWidthPx, captionRect.height());
+                if (isRtl) {
+                    return new Rect(captionRect.width() - elementWidthPx, 0,
+                            captionRect.width(), captionRect.height());
+                } else {
+                    return new Rect(0, 0, elementWidthPx, captionRect.height());
+                }
             }
             case END -> {
-                return new Rect(captionRect.width() - elementWidthPx, 0,
-                        captionRect.width(), captionRect.height());
+                if (isRtl) {
+                    return new Rect(0, 0, elementWidthPx, captionRect.height());
+                } else {
+                    return new Rect(captionRect.width() - elementWidthPx, 0,
+                            captionRect.width(), captionRect.height());
+                }
             }
         }
         throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
index 503ad92..5f25f42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
@@ -114,7 +114,7 @@
         // If handle is not in status bar region(i.e., bottom stage in vertical split),
         // do not create an input layer
         if (position.y >= SystemBarUtils.getStatusBarHeight(context)) return
-        if (!isCaptionVisible && statusBarInputLayerExists) {
+        if (!isCaptionVisible) {
             disposeStatusBarInputLayer()
             return
         }
@@ -227,6 +227,7 @@
      * is not visible.
      */
     fun disposeStatusBarInputLayer() {
+        if (!statusBarInputLayerExists) return
         statusBarInputLayerExists = false
         handler.post {
             statusBarInputLayer?.releaseView()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt
new file mode 100644
index 0000000..898964f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Bring apps to front by clicking on the App Header.
+ *
+ * Assert that the app windows move to front.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class BringDesktopAppsToFrontLandscape : BringDesktopAppsToFront(rotation = ROTATION_90) {
+
+    @ExpectedScenarios(["BRING_APPS_TO_FRONT"])
+    @Test
+    override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig()
+                .use(FlickerServiceConfig.DEFAULT)
+                .use(BRING_APPS_TO_FRONT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt
new file mode 100644
index 0000000..b123d7d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_0
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Bring apps to front by clicking on the App Header.
+ *
+ * Assert that the app windows move to front.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class BringDesktopAppsToFrontPortrait : BringDesktopAppsToFront(rotation = ROTATION_0) {
+
+    @ExpectedScenarios(["BRING_APPS_TO_FRONT"])
+    @Test
+    override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig()
+                .use(FlickerServiceConfig.DEFAULT)
+                .use(BRING_APPS_TO_FRONT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 4cddf31..88dc548 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -25,6 +25,7 @@
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
 import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd
 import android.tools.flicker.assertors.assertions.AppWindowBecomesInvisible
+import android.tools.flicker.assertors.assertions.AppWindowBecomesTopWindow
 import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible
 import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd
 import android.tools.flicker.assertors.assertions.AppWindowCoversRightHalfScreenAtEnd
@@ -345,6 +346,30 @@
                         ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
+        val BRING_APPS_TO_FRONT =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("BRING_APPS_TO_FRONT"),
+                extractor =
+                    ShellTransitionScenarioExtractor(
+                        transitionMatcher =
+                            object : ITransitionMatcher {
+                                override fun findAll(
+                                    transitions: Collection<Transition>
+                                ): Collection<Transition> {
+                                    return transitions.filter {
+                                        it.type == TransitionType.TO_FRONT
+                                    }
+                                }
+                            }
+                    ),
+                assertions =
+                    AssertionTemplates.COMMON_ASSERTIONS +
+                            listOf(
+                                AppWindowBecomesTopWindow(DESKTOP_MODE_APP),
+                                AppWindowOnTopAtEnd(DESKTOP_MODE_APP),
+                            ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
+            )
+
         val CASCADE_APP =
             FlickerConfigEntry(
                 scenarioId = ScenarioId("CASCADE_APP"),
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt
new file mode 100644
index 0000000..e1120bd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by dragging it to the top drag zone.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppWindowWithDragToTopDragZoneLandscape : MaximizeAppWindowWithDragToTopDragZone(
+    rotation = ROTATION_90
+) {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt
new file mode 100644
index 0000000..fb910c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by dragging it to the top drag zone.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppWindowWithDragToTopDragZonePortrait : MaximizeAppWindowWithDragToTopDragZone() {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
index e4ccc2c..6c8cc68 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
@@ -13,11 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.wm.shell.functional
 
-package com.android.systemui.keyboard.shortcut.shared.model
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.BringDesktopAppsToFront
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/** Functional test for [BringDesktopAppsToFront]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class BringDesktopAppsToFrontTest : BringDesktopAppsToFront()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt
new file mode 100644
index 0000000..7e0b81a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [MaximizeAppWindowWithDragToTopDragZone]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class MaximizeAppWindowWithDragToTopDragZoneTest : MaximizeAppWindowWithDragToTopDragZone()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt
new file mode 100644
index 0000000..1db22eb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.scenarios
+
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Test Base Class")
+abstract class BringDesktopAppsToFront(
+    val rotation: Rotation = Rotation.ROTATION_0,
+    isResizable: Boolean = true,
+    isLandscapeApp: Boolean = true,
+) : DesktopScenarioCustomAppTestBase(isResizable, isLandscapeApp) {
+
+    private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+
+    @Rule
+    @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(rotation.value)
+        ChangeDisplayOrientationRule.setRotation(rotation)
+        tapl.enableTransientTaskbar(false)
+        // Launch a first app and snap it to left side so that it doesn't overlap too much with
+        // the next launching app, and their headers are visible enough to switch focus by tapping
+        // on them.
+        testApp.enterDesktopMode(wmHelper, device)
+        testApp.snapResizeDesktopApp(wmHelper, device, instrumentation.context, toLeft = true)
+        mailApp.launchViaIntent(wmHelper)
+    }
+
+    @Test
+    open fun bringDesktopAppsToFront() {
+        testApp.bringToFront(wmHelper, device)
+        mailApp.bringToFront(wmHelper, device)
+        testApp.bringToFront(wmHelper, device)
+        mailApp.bringToFront(wmHelper, device)
+    }
+
+    @After
+    fun teardown() {
+        mailApp.exit(wmHelper)
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
index 351a700..f9bf49e 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
@@ -57,7 +57,7 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         nonResizeableApp.launchViaIntent(wmHelper)
     }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
index 3f9927f..16e5373 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
@@ -40,7 +40,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
index 6d52a11..c43a575 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt
@@ -47,7 +47,7 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
index 91cfd17..786a8b7 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt
@@ -36,7 +36,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
index 967bd29..0f546cd 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
@@ -49,7 +49,7 @@
 
     @Test
     open fun enterDesktopWithDrag() {
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopModeWithDrag(wmHelper, device)
     }
 
     @After
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
index f442fdb..2800839 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
@@ -46,7 +46,7 @@
             instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode))
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
index 6637b01..5cf51e3 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt
@@ -66,7 +66,7 @@
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
         ChangeDisplayOrientationRule.setRotation(rotation)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         testApp.cornerResize(
             wmHelper,
             device,
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
index a54d497..d2be494 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
@@ -58,7 +58,7 @@
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
         ChangeDisplayOrientationRule.setRotation(rotation)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt
new file mode 100644
index 0000000..60a0fb5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.internal.R
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * Base scenario test for maximizing a desktop app window by dragging it to the top drag zone.
+ */
+@Ignore("Test Base Class")
+abstract class MaximizeAppWindowWithDragToTopDragZone
+constructor(private val rotation: Rotation = Rotation.ROTATION_0) {
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val tapl = LauncherInstrumentation()
+    private val wmHelper = WindowManagerStateHelper(instrumentation)
+    private val device = UiDevice.getInstance(instrumentation)
+    private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+
+    @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        // Skip the test when the drag-to-maximize is disabled on this device.
+        Assume.assumeTrue(Flags.enableDragToMaximize() &&
+            instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode))
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(rotation.value)
+        ChangeDisplayOrientationRule.setRotation(rotation)
+        testApp.enterDesktopMode(wmHelper, device)
+    }
+
+    @Test
+    open fun maximizeAppWithDragToTopDragZone() {
+        testApp.maximizeAppWithDragToTopDragZone(wmHelper, device)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
index b548363..971637b 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt
@@ -61,7 +61,7 @@
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
         ChangeDisplayOrientationRule.setRotation(rotation)
-        testApp1.enterDesktopWithDrag(wmHelper, device)
+        testApp1.enterDesktopMode(wmHelper, device)
         testApp2.launchViaIntent(wmHelper)
         testApp3.launchViaIntent(wmHelper)
     }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
index b86765e..7987f7e 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt
@@ -58,7 +58,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
index aad266f..6ce36f5 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
@@ -61,7 +61,7 @@
         tapl.setExpectedRotation(rotation.value)
         tapl.enableTransientTaskbar(false)
         ChangeDisplayOrientationRule.setRotation(rotation)
-        firstApp.enterDesktopWithDrag(wmHelper, device)
+        firstApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
index bfee318..eefa0bb 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
@@ -61,7 +61,7 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
index 5b1b64e..0226eb3 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
@@ -65,7 +65,7 @@
         tapl.setExpectedRotation(rotation.value)
         // Set string extra to ensure the app is on PiP mode at launch
         pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true"))
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
         mailApp.launchViaIntent(wmHelper)
         newTasksApp.launchViaIntent(wmHelper)
         imeApp.launchViaIntent(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
index a7cebf4..6463623 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
@@ -67,7 +67,7 @@
         tapl.setEnableRotation(true)
         ChangeDisplayOrientationRule.setRotation(rotation)
         tapl.setExpectedRotation(rotation.value)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
index 6780238..f198cfe 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
@@ -60,7 +60,7 @@
         )
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(rotation.value)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
index 2b40497..fd4c243 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
@@ -56,7 +56,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
index b4bd7e1..62e860e 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
@@ -56,7 +56,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
index f08e50e..de330e0 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
@@ -59,7 +59,7 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(0)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
index ce235d4..4b3f15f 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
@@ -67,7 +67,7 @@
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
         tapl.setEnableRotation(true)
         tapl.setExpectedRotation(0)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
index 0051952..a108367 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
@@ -62,7 +62,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
index dad2eb6..1455bd1 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
@@ -54,7 +54,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        testApp.enterDesktopMode(wmHelper, device)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt
new file mode 100644
index 0000000..528ca7e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell
+
+import com.android.wm.shell.common.ShellExecutor
+
+/**
+ * Test ShellExecutor that runs everything synchronously.
+ */
+class TestSyncExecutor : ShellExecutor {
+    override fun execute(runnable: Runnable) {
+        runnable.run()
+    }
+
+    override fun executeDelayed(runnable: Runnable, delayMillis: Long) {
+        runnable.run()
+    }
+
+    override fun removeCallbacks(runnable: Runnable) {
+    }
+
+    override fun hasCallback(runnable: Runnable): Boolean {
+        return false
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt
new file mode 100644
index 0000000..75025d90
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.annotation.ColorRes
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
+import com.android.internal.R
+import com.android.wm.shell.ShellTestCase
+import java.util.function.Consumer
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+
+/**
+ * Tests for [LetterboxConfiguration].
+ *
+ * Build/Install/Run:
+ *  atest WMShellUnitTests:LetterboxConfigurationTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LetterboxConfigurationTest : ShellTestCase() {
+
+    companion object {
+        @JvmStatic
+        val COLOR_WHITE = Color.valueOf(Color.WHITE)
+        @JvmStatic
+        val COLOR_RED = Color.valueOf(Color.RED)
+        @JvmStatic
+        val COLOR_BLACK = Color.valueOf(Color.BLACK)
+        @JvmStatic
+        val COLOR_WHITE_RESOURCE_ID = android.R.color.white
+        @JvmStatic
+        val COLOR_BLACK_RESOURCE_ID = android.R.color.black
+    }
+
+    @Test
+    fun `default background color is used if override is not set`() {
+        runTestScenario { r ->
+            r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+            r.loadConfiguration()
+            r.checkBackgroundColor(COLOR_WHITE)
+        }
+    }
+
+    @Test
+    fun `overridden background color is used if set`() {
+        runTestScenario { r ->
+            r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+            r.loadConfiguration()
+            r.overrideBackgroundColor(COLOR_RED)
+            r.checkBackgroundColor(COLOR_RED)
+        }
+    }
+
+    @Test
+    fun `overridden background color resource is used if set without override`() {
+        runTestScenario { r ->
+            r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+            r.loadConfiguration()
+            r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+            r.checkBackgroundColor(COLOR_BLACK)
+        }
+    }
+
+    @Test
+    fun `overridden background color has precedence over color id`() {
+        runTestScenario { r ->
+            r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+            r.loadConfiguration()
+            r.overrideBackgroundColor(COLOR_RED)
+            r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+            r.checkBackgroundColor(COLOR_RED)
+        }
+    }
+
+    @Test
+    fun `reset background color`() {
+        runTestScenario { r ->
+            r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID)
+            r.loadConfiguration()
+            r.overrideBackgroundColor(COLOR_RED)
+            r.checkBackgroundColor(COLOR_RED)
+
+            r.resetBackgroundColor()
+            r.checkBackgroundColor(COLOR_WHITE)
+
+            r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID)
+            r.checkBackgroundColor(COLOR_BLACK)
+
+            r.resetBackgroundColor()
+            r.checkBackgroundColor(COLOR_WHITE)
+        }
+    }
+
+    /**
+     * Runs a test scenario providing a Robot.
+     */
+    fun runTestScenario(consumer: Consumer<LetterboxConfigurationRobotTest>) {
+        val robot = LetterboxConfigurationRobotTest(mContext)
+        consumer.accept(robot)
+    }
+
+    class LetterboxConfigurationRobotTest(private val ctx: Context) {
+
+        private val resources: Resources
+        private lateinit var letterboxConfig: LetterboxConfiguration
+
+        init {
+            resources = ctx.resources
+            spyOn(resources)
+        }
+
+        fun setDefaultBackgroundColorId(@ColorRes colorId: Int) {
+            doReturn(colorId).`when`(resources)
+                .getColor(R.color.config_letterboxBackgroundColor, null)
+        }
+
+        fun loadConfiguration() {
+            letterboxConfig = LetterboxConfiguration(ctx)
+        }
+
+        fun overrideBackgroundColor(color: Color) {
+            letterboxConfig.setLetterboxBackgroundColor(color)
+        }
+
+        fun resetBackgroundColor() {
+            letterboxConfig.resetLetterboxBackgroundColor()
+        }
+
+        fun overrideBackgroundColorId(@ColorRes colorId: Int) {
+            letterboxConfig.setLetterboxBackgroundColorResourceId(colorId)
+        }
+
+        fun checkBackgroundColor(expected: Color) {
+            val colorComponents = letterboxConfig.getBackgroundColorRgbArray()
+            val expectedComponents = expected.components
+            assert(expectedComponents.contentEquals(colorComponents))
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
new file mode 100644
index 0000000..1ae1c3f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.compatui.letterbox
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.WindowManager.TRANSIT_CLOSE
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.TransitionObserverInputBuilder
+import com.android.wm.shell.util.executeTransitionObserverTest
+import java.util.function.Consumer
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
+import org.mockito.kotlin.anyOrNull
+import org.mockito.verification.VerificationMode
+
+/**
+ * Tests for [LetterboxTransitionObserver].
+ *
+ * Build/Install/Run:
+ *  atest WMShellUnitTests:LetterboxTransitionObserverTest
+ */
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class LetterboxTransitionObserverTest : ShellTestCase() {
+
+    @get:Rule
+    val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
+    @Test
+    @DisableFlags(Flags.FLAG_APP_COMPAT_REFACTORING)
+    fun `when initialized and flag disabled the observer is not registered`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+                r.checkObservableIsRegistered(expected = false)
+            }
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_APP_COMPAT_REFACTORING)
+    fun `when initialized and flag enabled the observer is registered`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+                r.checkObservableIsRegistered(expected = true)
+            }
+        }
+    }
+
+    @Test
+    fun `LetterboxController not used without TaskInfos in Change`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+
+                inputBuilder {
+                    buildTransitionInfo()
+                    addChange(createChange())
+                    addChange(createChange())
+                    addChange(createChange())
+                }
+
+                validateOutput {
+                    r.creationEventDetected(expected = false)
+                    r.visibilityEventDetected(expected = false)
+                    r.destroyEventDetected(expected = false)
+                    r.boundsEventDetected(expected = false)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun `When a topActivity is letterboxed surfaces creation is requested`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+
+                inputBuilder {
+                    buildTransitionInfo()
+                    r.createTopActivityChange(inputBuilder = this, isLetterboxed = true)
+                }
+
+                validateOutput {
+                    r.creationEventDetected(expected = true)
+                    r.visibilityEventDetected(expected = true, visible = true)
+                    r.destroyEventDetected(expected = false)
+                    r.boundsEventDetected(expected = true)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun `When a topActivity is not letterboxed visibility is updated`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+
+                inputBuilder {
+                    buildTransitionInfo()
+                    r.createTopActivityChange(inputBuilder = this, isLetterboxed = false)
+                }
+
+                validateOutput {
+                    r.creationEventDetected(expected = false)
+                    r.visibilityEventDetected(expected = true, visible = false)
+                    r.destroyEventDetected(expected = false)
+                    r.boundsEventDetected(expected = false)
+                }
+            }
+        }
+    }
+
+    @Test
+    fun `When closing change letterbox surface destroy is triggered`() {
+        runTestScenario { r ->
+            executeTransitionObserverTest(observerFactory = r.observerFactory) {
+                r.invokeShellInit()
+
+                inputBuilder {
+                    buildTransitionInfo()
+                    r.createClosingChange(inputBuilder = this)
+                }
+
+                validateOutput {
+                    r.destroyEventDetected(expected = true)
+                    r.creationEventDetected(expected = false)
+                    r.visibilityEventDetected(expected = false, visible = false)
+                    r.boundsEventDetected(expected = false)
+                }
+            }
+        }
+    }
+
+    /**
+     * Runs a test scenario providing a Robot.
+     */
+    fun runTestScenario(consumer: Consumer<LetterboxTransitionObserverRobotTest>) {
+        val robot = LetterboxTransitionObserverRobotTest()
+        consumer.accept(robot)
+    }
+
+    class LetterboxTransitionObserverRobotTest {
+
+        companion object {
+            @JvmStatic
+            private val DISPLAY_ID = 1
+
+            @JvmStatic
+            private val TASK_ID = 20
+        }
+
+        private val executor: ShellExecutor
+        private val shellInit: ShellInit
+        private val transitions: Transitions
+        private val letterboxController: LetterboxController
+        private val letterboxObserver: LetterboxTransitionObserver
+
+        val observerFactory: () -> LetterboxTransitionObserver
+
+        init {
+            executor = Mockito.mock(ShellExecutor::class.java)
+            shellInit = ShellInit(executor)
+            transitions = Mockito.mock(Transitions::class.java)
+            letterboxController = Mockito.mock(LetterboxController::class.java)
+            letterboxObserver =
+                LetterboxTransitionObserver(shellInit, transitions, letterboxController)
+            observerFactory = { letterboxObserver }
+        }
+
+        fun invokeShellInit() = shellInit.init()
+
+        fun observer() = letterboxObserver
+
+        fun checkObservableIsRegistered(expected: Boolean) {
+            Mockito.verify(transitions, expected.asMode()).registerObserver(observer())
+        }
+
+        fun creationEventDetected(
+            expected: Boolean,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID
+        ) {
+            Mockito.verify(letterboxController, expected.asMode()).createLetterboxSurface(
+                toLetterboxKeyMatcher(displayId, taskId),
+                anyOrNull(),
+                anyOrNull()
+            )
+        }
+
+        fun visibilityEventDetected(
+            expected: Boolean,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID,
+            visible: Boolean? = null
+        ) {
+            Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceVisibility(
+                toLetterboxKeyMatcher(displayId, taskId),
+                anyOrNull(),
+                visible.asMatcher()
+            )
+        }
+
+        fun destroyEventDetected(
+            expected: Boolean,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID
+        ) {
+            Mockito.verify(letterboxController, expected.asMode()).destroyLetterboxSurface(
+                toLetterboxKeyMatcher(displayId, taskId),
+                anyOrNull()
+            )
+        }
+
+        fun boundsEventDetected(
+            expected: Boolean,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID
+        ) {
+            Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceBounds(
+                toLetterboxKeyMatcher(displayId, taskId),
+                anyOrNull(),
+                anyOrNull()
+            )
+        }
+
+        fun createTopActivityChange(
+            inputBuilder: TransitionObserverInputBuilder,
+            isLetterboxed: Boolean = true,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID
+        ) {
+            inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply {
+                appCompatTaskInfo.isTopActivityLetterboxed = isLetterboxed
+                this.taskId = taskId
+                this.displayId = displayId
+            })
+        }
+
+        fun createClosingChange(
+            inputBuilder: TransitionObserverInputBuilder,
+            displayId: Int = DISPLAY_ID,
+            taskId: Int = TASK_ID
+        ) {
+            inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply {
+                this.taskId = taskId
+                this.displayId = displayId
+            }, changeMode = TRANSIT_CLOSE)
+        }
+
+        private fun Boolean.asMode(): VerificationMode = if (this) times(1) else never()
+
+        private fun Boolean?.asMatcher(): Boolean =
+            if (this != null) eq(this) else any()
+
+        private fun toLetterboxKeyMatcher(displayId: Int, taskId: Int): LetterboxKey {
+            if (displayId < 0 || taskId < 0) {
+                return any()
+            } else {
+                return eq(LetterboxKey(displayId, taskId))
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index f21f264..62717a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -31,6 +31,8 @@
 import android.testing.TestableLooper.RunWithLooper
 import android.view.SurfaceControl
 import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_NONE
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.view.WindowManager.TransitionType
@@ -47,6 +49,7 @@
 import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.util.StubTransaction
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNull
@@ -491,6 +494,72 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun startLaunchTransition_unknownLaunchingTask_animates() {
+        val wct = WindowContainerTransaction()
+        val task = createTask(WINDOWING_MODE_FREEFORM)
+        val transition = Binder()
+        whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+            .thenReturn(transition)
+        whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any()))
+            .thenReturn(mock())
+
+        mixedHandler.startLaunchTransition(
+            transitionType = TRANSIT_OPEN,
+            wct = wct,
+            taskId = null,
+        )
+
+        val started = mixedHandler.startAnimation(
+            transition,
+            createTransitionInfo(
+                TRANSIT_OPEN,
+                listOf(createChange(task, mode = TRANSIT_OPEN))
+            ),
+            StubTransaction(),
+            StubTransaction(),
+        ) { }
+
+        assertThat(started).isEqualTo(true)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+    fun startLaunchTransition_unknownLaunchingTaskOverImmersive_animatesImmersiveChange() {
+        val wct = WindowContainerTransaction()
+        val immersiveTask = createTask(WINDOWING_MODE_FREEFORM)
+        val openingTask = createTask(WINDOWING_MODE_FREEFORM)
+        val transition = Binder()
+        whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+            .thenReturn(transition)
+        whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any()))
+            .thenReturn(mock())
+
+        mixedHandler.startLaunchTransition(
+            transitionType = TRANSIT_OPEN,
+            wct = wct,
+            taskId = null,
+            exitingImmersiveTask = immersiveTask.taskId,
+        )
+
+        val immersiveChange = createChange(immersiveTask, mode = TRANSIT_CHANGE)
+        val openingChange = createChange(openingTask, mode = TRANSIT_OPEN)
+        val started = mixedHandler.startAnimation(
+            transition,
+            createTransitionInfo(
+                TRANSIT_OPEN,
+                listOf(immersiveChange, openingChange)
+            ),
+            StubTransaction(),
+            StubTransaction(),
+        ) { }
+
+        assertThat(started).isEqualTo(true)
+        verify(desktopImmersiveController)
+            .animateResizeChange(eq(immersiveChange), any(), any(), any())
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS)
     fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() {
         val wct = WindowContainerTransaction()
@@ -712,9 +781,13 @@
         changes.forEach { change -> addChange(change) }
     }
 
-    private fun createChange(task: RunningTaskInfo): TransitionInfo.Change =
+    private fun createChange(
+        task: RunningTaskInfo,
+        @TransitionInfo.TransitionMode mode: Int = TRANSIT_NONE
+    ): TransitionInfo.Change =
         TransitionInfo.Change(task.token, SurfaceControl()).apply {
             taskInfo = task
+            setMode(mode)
         }
 
     private fun createTask(@WindowingMode windowingMode: Int): RunningTaskInfo =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
new file mode 100644
index 0000000..9e63a6d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.content.pm.ActivityInfo
+import android.graphics.Rect
+import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyGestureEventHandler
+import android.hardware.input.KeyGestureEvent
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.KeyEvent
+import android.window.DisplayAreaInfo
+import androidx.test.filters.SmallTest
+import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
+import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
+import com.android.wm.shell.MockToken
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
+import com.android.wm.shell.transition.FocusTransitionObserver
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel
+import java.util.Optional
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.quality.Strictness
+
+/**
+ * Test class for [DesktopModeKeyGestureHandler]
+ *
+ * Usage: atest WMShellUnitTests:DesktopModeKeyGestureHandlerTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@ExperimentalCoroutinesApi
+@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
+
+    @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+    private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
+    private val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+    private val focusTransitionObserver = mock<FocusTransitionObserver>()
+    private val testExecutor = mock<ShellExecutor>()
+    private val inputManager = mock<InputManager>()
+    private val displayController = mock<DisplayController>()
+    private val displayLayout = mock<DisplayLayout>()
+    private val desktopModeWindowDecorViewModel = mock<DesktopModeWindowDecorViewModel>()
+    private val desktopTasksController = mock<DesktopTasksController>()
+
+    private lateinit var desktopModeKeyGestureHandler: DesktopModeKeyGestureHandler
+    private lateinit var keyGestureEventHandler: KeyGestureEventHandler
+    private lateinit var mockitoSession: StaticMockitoSession
+    private lateinit var testScope: CoroutineScope
+    private lateinit var shellInit: ShellInit
+
+    // Mock running tasks are registered here so we can get the list from mock shell task organizer
+    private val runningTasks = mutableListOf<RunningTaskInfo>()
+
+    @Before
+    fun setUp() {
+        Dispatchers.setMain(StandardTestDispatcher())
+        mockitoSession =
+            mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .spyStatic(DesktopModeStatus::class.java)
+                .startMocking()
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+        testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
+        shellInit = spy(ShellInit(testExecutor))
+
+        whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
+        whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
+        whenever(displayLayout.getStableBounds(any())).thenAnswer { i ->
+            (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+        }
+        val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
+        tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+        whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
+
+        doAnswer {
+            keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
+            null
+        }.whenever(inputManager).registerKeyGestureEventHandler(any())
+        shellInit.init()
+    }
+
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+
+        runningTasks.clear()
+        testScope.cancel()
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
+        FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER
+    )
+    fun keyGestureMoveToNextDisplay_shouldMoveToNextDisplay() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        // Set up two display ids
+        whenever(rootTaskDisplayAreaOrganizer.displayIds)
+            .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
+        // Create a mock for the target display area: default display
+        val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
+        whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
+            .thenReturn(defaultDisplayArea)
+        // Setup a focused task on secondary display, which is expected to move to default display
+        val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY)
+            .setDisplayId(SECOND_DISPLAY)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D))
+            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopTasksController).moveToNextDisplay(task.taskId)
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureSnapLeft_shouldSnapResizeTaskToLeft() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, true, null)
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureSnapRight_shouldSnapResizeTaskToRight() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, false, null)
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureToggleFreeformWindowSize_shouldToggleTaskSize() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_EQUALS))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopTasksController).toggleDesktopTaskSize(
+            task,
+            ResizeTrigger.MAXIMIZE_MENU,
+            null
+        )
+    }
+
+    @Test
+    @EnableFlags(
+        FLAG_USE_KEY_GESTURE_EVENT_HANDLER,
+        FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS
+    )
+    fun keyGestureMinimizeFreeformWindow_shouldMinimizeTask() {
+        desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler(
+            context,
+            Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController),
+            inputManager, shellTaskOrganizer, focusTransitionObserver
+        )
+        val task = setUpFreeformTask()
+        task.isFocused = true
+        whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
+        whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
+
+        val event = KeyGestureEvent.Builder()
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_MINUS))
+            .setModifierState(KeyEvent.META_META_ON)
+            .build()
+        val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+
+        assertThat(result).isTrue()
+        verify(desktopTasksController).minimizeTask(task)
+    }
+
+    private fun setUpFreeformTask(
+        displayId: Int = DEFAULT_DISPLAY,
+        bounds: Rect? = null,
+    ): RunningTaskInfo {
+        val task = createFreeformTask(displayId, bounds)
+        val activityInfo = ActivityInfo()
+        task.topActivityInfo = activityInfo
+        whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+        runningTasks.add(task)
+        return task
+    }
+
+    private companion object {
+        const val SECOND_DISPLAY = 2
+        val STABLE_BOUNDS = Rect(0, 0, 1000, 1000)
+    }
+}
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 ad266ea..93999476 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
@@ -36,12 +36,10 @@
 import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
 import android.content.res.Configuration.ORIENTATION_LANDSCAPE
 import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.content.res.Resources
 import android.graphics.Point
 import android.graphics.PointF
 import android.graphics.Rect
-import android.hardware.input.InputManager
-import android.hardware.input.InputManager.KeyGestureEventHandler
-import android.hardware.input.KeyGestureEvent
 import android.os.Binder
 import android.os.Bundle
 import android.os.Handler
@@ -53,7 +51,6 @@
 import android.view.Display.DEFAULT_DISPLAY
 import android.view.DragEvent
 import android.view.Gravity
-import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.SurfaceControl
 import android.view.WindowInsets
@@ -63,6 +60,7 @@
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.widget.Toast
 import android.window.DisplayAreaInfo
 import android.window.IWindowContainerToken
 import android.window.RemoteTransition
@@ -75,18 +73,14 @@
 import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
 import android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID
 import androidx.test.filters.SmallTest
-import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
 import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.dx.mockito.inline.extended.ExtendedMockito.never
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
-import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
-import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
 import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
-import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
 import com.android.wm.shell.MockToken
 import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -96,10 +90,10 @@
 import com.android.wm.shell.TestShellExecutor
 import com.android.wm.shell.common.DisplayController
 import com.android.wm.shell.common.DisplayLayout
-import com.android.wm.shell.common.LaunchAdjacentController
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
 import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
@@ -123,7 +117,6 @@
 import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellController
 import com.android.wm.shell.sysui.ShellInit
-import com.android.wm.shell.transition.FocusTransitionObserver
 import com.android.wm.shell.transition.OneShotRemoteHandler
 import com.android.wm.shell.transition.TestRemoteTransition
 import com.android.wm.shell.transition.Transitions
@@ -167,6 +160,7 @@
 import org.mockito.Mockito.times
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.atLeastOnce
 import org.mockito.kotlin.capture
 import org.mockito.kotlin.eq
@@ -206,12 +200,10 @@
   @Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler
   @Mock
   lateinit var mMockDesktopImmersiveController: DesktopImmersiveController
-  @Mock lateinit var launchAdjacentController: LaunchAdjacentController
   @Mock lateinit var splitScreenController: SplitScreenController
   @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler
   @Mock lateinit var dragAndDropController: DragAndDropController
   @Mock lateinit var multiInstanceHelper: MultiInstanceHelper
-  @Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver
   @Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator
   @Mock lateinit var recentTasksController: RecentTasksController
   @Mock
@@ -222,23 +214,21 @@
   @Mock private lateinit var mockHandler: Handler
   @Mock private lateinit var desktopModeEventLogger: DesktopModeEventLogger
   @Mock lateinit var persistentRepository: DesktopPersistentRepository
-  @Mock private lateinit var mockInputManager: InputManager
-  @Mock private lateinit var mockFocusTransitionObserver: FocusTransitionObserver
   @Mock lateinit var motionEvent: MotionEvent
   @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer
-
+  @Mock private lateinit var mockToast: Toast
   private lateinit var mockitoSession: StaticMockitoSession
   @Mock
   private lateinit var desktopTilingDecorViewModel: DesktopTilingDecorViewModel
   @Mock
   private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration
+  @Mock private lateinit var resources: Resources
   private lateinit var controller: DesktopTasksController
   private lateinit var shellInit: ShellInit
   private lateinit var taskRepository: DesktopRepository
   private lateinit var desktopTasksLimiter: DesktopTasksLimiter
   private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener
   private lateinit var testScope: CoroutineScope
-  private lateinit var keyGestureEventHandler: KeyGestureEventHandler
 
   private val shellExecutor = TestShellExecutor()
 
@@ -261,6 +251,7 @@
         mockitoSession()
             .strictness(Strictness.LENIENT)
             .spyStatic(DesktopModeStatus::class.java)
+            .spyStatic(Toast::class.java)
             .startMocking()
     doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
@@ -288,26 +279,22 @@
     whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn(
       Desktop.getDefaultInstance()
     )
+    doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
 
     val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
     tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
     whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(any(), any<RunningTaskInfo>()))
-      .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
+      .thenReturn(ExitResult.NoExit)
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull()))
-      .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
+      .thenReturn(ExitResult.NoExit)
 
     controller = createController()
     controller.setSplitScreenController(splitScreenController)
     controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter
 
-    doAnswer {
-      keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
-      null
-    }.whenever(mockInputManager).registerKeyGestureEventHandler(any())
-
     shellInit.init()
 
     val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java)
@@ -341,8 +328,6 @@
         dragToDesktopTransitionHandler,
         mMockDesktopImmersiveController,
         taskRepository,
-        desktopModeLoggerTransitionObserver,
-        launchAdjacentController,
         recentsTransitionHandler,
         multiInstanceHelper,
         shellExecutor,
@@ -350,8 +335,6 @@
         recentTasksController,
         mockInteractionJankMonitor,
         mockHandler,
-        mockInputManager,
-        mockFocusTransitionObserver,
         desktopModeEventLogger,
         desktopTilingDecorViewModel,
       )
@@ -1556,44 +1539,6 @@
   }
 
   @Test
-  @EnableFlags(
-    FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS,
-    FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT,
-    FLAG_USE_KEY_GESTURE_EVENT_HANDLER
-  )
-  fun moveToNextDisplay_withKeyGesture() {
-    // Set up two display ids
-    whenever(rootTaskDisplayAreaOrganizer.displayIds)
-      .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
-    // Create a mock for the target display area: default display
-    val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
-    whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
-      .thenReturn(defaultDisplayArea)
-    // Setup a focused task on secondary display, which is expected to move to default display
-    val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
-    task.isFocused = true
-    whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task))
-    whenever(mockFocusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true)
-
-    val event = KeyGestureEvent.Builder()
-        .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY)
-        .setDisplayId(SECOND_DISPLAY)
-        .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D))
-        .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
-        .build()
-    val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
-
-    assertThat(result).isTrue()
-    with(getLatestWct(type = TRANSIT_CHANGE)) {
-      assertThat(hierarchyOps).hasSize(1)
-      assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
-      assertThat(hierarchyOps[0].isReparent).isTrue()
-      assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder())
-      assertThat(hierarchyOps[0].toTop).isTrue()
-    }
-  }
-
-  @Test
   fun getTaskWindowingMode() {
     val fullscreenTask = setUpFullscreenTask()
     val freeformTask = setUpFreeformTask()
@@ -1833,7 +1778,8 @@
     whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
       .thenReturn(transition)
     whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task)))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = task.taskId,
         runOnTransitionStart = runOnTransit,
       ))
@@ -3214,13 +3160,43 @@
   fun newWindow_fromFreeformAddsNewWindow() {
     setUpLandscapeDisplay()
     val task = setUpFreeformTask()
-    val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+    val wctCaptor = argumentCaptor<WindowContainerTransaction>()
+    val transition = Binder()
+    whenever(mMockDesktopImmersiveController
+      .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull()))
+      .thenReturn(ExitResult.NoExit)
+    whenever(desktopMixedTransitionHandler
+      .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull()))
+      .thenReturn(transition)
+
     runOpenNewWindow(task)
-    verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull())
-    assertThat(ActivityOptions.fromBundle(wctCaptor.value.hierarchyOps[0].launchOptions)
+
+    verify(desktopMixedTransitionHandler)
+      .startLaunchTransition(anyInt(), wctCaptor.capture(), anyOrNull(), anyOrNull(), anyOrNull())
+    assertThat(ActivityOptions.fromBundle(wctCaptor.firstValue.hierarchyOps[0].launchOptions)
       .launchWindowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
   }
 
+  @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
+  fun newWindow_fromFreeform_exitsImmersiveIfNeeded() {
+    setUpLandscapeDisplay()
+    val immersiveTask = setUpFreeformTask()
+    val task = setUpFreeformTask()
+    val runOnStart = RunOnStartTransitionCallback()
+    val transition = Binder()
+    whenever(mMockDesktopImmersiveController
+      .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull()))
+      .thenReturn(ExitResult.Exit(immersiveTask.taskId, runOnStart))
+    whenever(desktopMixedTransitionHandler
+      .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull()))
+      .thenReturn(transition)
+
+    runOpenNewWindow(task)
+
+    runOnStart.assertOnlyInvocation(transition)
+  }
+
   private fun runOpenNewWindow(task: RunningTaskInfo) {
     markTaskVisible(task)
     task.baseActivity = mock(ComponentName::class.java)
@@ -3314,7 +3290,8 @@
       .thenReturn(transition)
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId)))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = immersiveTask.taskId,
         runOnTransitionStart = runOnStartTransit,
       ))
@@ -3431,7 +3408,7 @@
 
   @Test
   @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING, Flags.FLAG_ENABLE_TILE_RESIZING)
-  fun handleSnapResizingTask_nonResizable_snapsToHalfScreen() {
+  fun handleSnapResizingTaskOnDrag_nonResizable_snapsToHalfScreen() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
       isResizeable = false
     }
@@ -3440,7 +3417,7 @@
     val expectedBounds =
       Rect(STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom)
 
-    controller.handleSnapResizingTask(
+    controller.handleSnapResizingTaskOnDrag(
 
       task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
       desktopWindowDecoration
@@ -3459,14 +3436,14 @@
 
   @Test
   @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
-  fun handleSnapResizingTask_nonResizable_startsRepositionAnimation() {
+  fun handleSnapResizingTaskOnDrag_nonResizable_startsRepositionAnimation() {
     val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply {
       isResizeable = false
     }
     val preDragBounds = Rect(100, 100, 400, 500)
     val currentDragBounds = Rect(0, 100, 300, 500)
 
-    controller.handleSnapResizingTask(
+    controller.handleSnapResizingTaskOnDrag(
       task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent,
       desktopWindowDecoration)
     verify(mReturnToDragStartAnimator).start(
@@ -3486,6 +3463,59 @@
   }
 
   @Test
+  @EnableFlags(
+    Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING
+  )
+  fun handleInstantSnapResizingTask_nonResizable_animatorNotStartedAndShowsToast() {
+    val taskBounds = Rect(0, 0, 200, 100)
+    val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+      isResizeable = false
+    }
+
+    controller.handleInstantSnapResizingTask(
+      task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+
+    // Assert that task is NOT updated via WCT
+    verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+    verify(mockToast).show()
+  }
+
+  @Test
+  @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
+  @DisableFlags(Flags.FLAG_ENABLE_TILE_RESIZING)
+  fun handleInstantSnapResizingTask_resizable_snapsToHalfScreenAndNotShowToast() {
+    val taskBounds = Rect(0, 0, 200, 100)
+    val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply {
+      isResizeable = true
+    }
+    val expectedBounds = Rect(
+      STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom
+    )
+
+    controller.handleInstantSnapResizingTask(
+      task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration)
+
+    // Assert bounds set to half of the stable bounds
+    val wct = getLatestToggleResizeDesktopTaskWct(taskBounds)
+    assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
+    verify(mockToast, never()).show()
+    verify(desktopModeEventLogger, times(1)).logTaskResizingStarted(
+      ResizeTrigger.SNAP_LEFT_MENU,
+      motionEvent,
+      task,
+      displayController
+    )
+    verify(desktopModeEventLogger, times(1)).logTaskResizingEnded(
+      ResizeTrigger.SNAP_LEFT_MENU,
+      motionEvent,
+      task,
+      expectedBounds.height(),
+      expectedBounds.width(),
+      displayController
+    )
+  }
+
+  @Test
   fun toggleBounds_togglesToCalculatedBoundsForNonResizable() {
     val bounds = Rect(0, 0, 200, 100)
     val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply {
@@ -3719,7 +3749,8 @@
     val transition = Binder()
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = 5,
         runOnTransitionStart = runOnStartTransit,
       ))
@@ -3740,7 +3771,8 @@
     val transition = Binder()
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = 5,
         runOnTransitionStart = runOnStartTransit,
       ))
@@ -3760,7 +3792,8 @@
     val transition = Binder()
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = 5,
         runOnTransitionStart = runOnStartTransit,
       ))
@@ -3782,7 +3815,8 @@
     val transition = Binder()
     whenever(mMockDesktopImmersiveController
       .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
-      .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+      .thenReturn(
+        ExitResult.Exit(
         exitingTask = 5,
         runOnTransitionStart = runOnStartTransit,
       ))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
index a4008c1..72c4666 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -39,6 +40,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.wm.shell.R;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip2.phone.PipAppIconOverlay;
 
@@ -49,33 +51,25 @@
 import org.mockito.MockitoAnnotations;
 
 /**
- * Unit test again {@link PipEnterAnimator}.
+ * Unit test against {@link PipEnterAnimator}.
  */
 @SmallTest
 @TestableLooper.RunWithLooper
 @RunWith(AndroidTestingRunner.class)
 public class PipEnterAnimatorTest {
+    private static final float TEST_CORNER_RADIUS = 1f;
+    private static final float TEST_SHADOW_RADIUS = 2f;
 
     @Mock private Context mMockContext;
-
     @Mock private Resources mMockResources;
-
     @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
-
     @Mock private SurfaceControl.Transaction mMockAnimateTransaction;
-
     @Mock private SurfaceControl.Transaction mMockStartTransaction;
-
     @Mock private SurfaceControl.Transaction mMockFinishTransaction;
-
     @Mock private Runnable mMockStartCallback;
-
     @Mock private Runnable mMockEndCallback;
-
     @Mock private PipAppIconOverlay mMockPipAppIconOverlay;
-
     @Mock private SurfaceControl mMockAppIconOverlayLeash;
-
     @Mock private ActivityInfo mMockActivityInfo;
 
     @Surface.Rotation private int mRotation;
@@ -89,13 +83,15 @@
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockResources.getInteger(anyInt())).thenReturn(0);
         when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction);
-        when(mMockAnimateTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockAnimateTransaction);
-        when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockStartTransaction);
-        when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockFinishTransaction);
         when(mMockPipAppIconOverlay.getLeash()).thenReturn(mMockAppIconOverlayLeash);
+        when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius))
+                .thenReturn((int) TEST_CORNER_RADIUS);
+        when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius))
+                .thenReturn((int) TEST_SHADOW_RADIUS);
+
+        prepareTransaction(mMockAnimateTransaction);
+        prepareTransaction(mMockStartTransaction);
+        prepareTransaction(mMockFinishTransaction);
 
         mTestLeash = new SurfaceControl.Builder()
                 .setContainerLayer()
@@ -122,6 +118,12 @@
 
         verify(mMockStartCallback).run();
         verifyZeroInteractions(mMockEndCallback);
+
+        // Check corner and shadow radii were set
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
     }
 
     @Test
@@ -142,6 +144,12 @@
 
         verify(mMockStartCallback).run();
         verify(mMockEndCallback).run();
+
+        // Check corner and shadow radii were set
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
     }
 
     @Test
@@ -197,5 +205,21 @@
 
         verify(mMockPipAppIconOverlay).onAnimationUpdate(
                 eq(mMockAnimateTransaction), anyFloat(), eq(fraction), eq(mEndBounds));
+
+        // Check corner and shadow radii were set
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+    }
+
+    // set up transaction chaining
+    private void prepareTransaction(SurfaceControl.Transaction tx) {
+        when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+                .thenReturn(tx);
+        when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat()))
+                .thenReturn(tx);
+        when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat()))
+                .thenReturn(tx);
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
index 0adb50b..23fbad0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java
@@ -16,15 +16,18 @@
 
 package com.android.wm.shell.pip2.animation;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 import static org.mockito.kotlin.MatchersKt.eq;
-import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
@@ -34,12 +37,14 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.wm.shell.R;
 import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -52,40 +57,40 @@
 public class PipResizeAnimatorTest {
 
     private static final float FLOAT_COMPARISON_DELTA = 0.001f;
+    private static final float TEST_CORNER_RADIUS = 1f;
+    private static final float TEST_SHADOW_RADIUS = 2f;
 
     @Mock private Context mMockContext;
-
+    @Mock private Resources mMockResources;
     @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
-
     @Mock private SurfaceControl.Transaction mMockTransaction;
-
     @Mock private SurfaceControl.Transaction mMockStartTransaction;
-
     @Mock private SurfaceControl.Transaction mMockFinishTransaction;
-
     @Mock private Runnable mMockStartCallback;
-
     @Mock private Runnable mMockEndCallback;
 
+    @Captor private ArgumentCaptor<Matrix> mArgumentCaptor;
+
     private PipResizeAnimator mPipResizeAnimator;
     private Rect mBaseBounds;
     private Rect mStartBounds;
     private Rect mEndBounds;
     private SurfaceControl mTestLeash;
-    private ArgumentCaptor<Matrix> mArgumentCaptor;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockFactory.getTransaction()).thenReturn(mMockTransaction);
-        when(mMockTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockTransaction);
-        when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockStartTransaction);
-        when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
-                .thenReturn(mMockFinishTransaction);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius))
+                .thenReturn((int) TEST_CORNER_RADIUS);
+        when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius))
+                .thenReturn((int) TEST_SHADOW_RADIUS);
 
-        mArgumentCaptor = ArgumentCaptor.forClass(Matrix.class);
+        prepareTransaction(mMockTransaction);
+        prepareTransaction(mMockStartTransaction);
+        prepareTransaction(mMockFinishTransaction);
+
         mTestLeash = new SurfaceControl.Builder()
                 .setContainerLayer()
                 .setName("PipResizeAnimatorTest")
@@ -187,6 +192,12 @@
         assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
         assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
         assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+        // Check corner and shadow radii were set
+        verify(mMockTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
     }
 
     @Test
@@ -237,6 +248,12 @@
         assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA);
         assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA);
         assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA);
+
+        // Check corner and shadow radii were set
+        verify(mMockTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
     }
 
     @Test
@@ -272,5 +289,21 @@
         mArgumentCaptor.getValue().getValues(matrix);
         assertEquals(matrix[Matrix.MSKEW_X], 0f, FLOAT_COMPARISON_DELTA);
         assertEquals(matrix[Matrix.MSKEW_Y], 0f, FLOAT_COMPARISON_DELTA);
+
+        // Check corner and shadow radii were set
+        verify(mMockTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+    }
+
+    // set up transaction chaining
+    private void prepareTransaction(SurfaceControl.Transaction tx) {
+        when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+                .thenReturn(tx);
+        when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat()))
+                .thenReturn(tx);
+        when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat()))
+                .thenReturn(tx);
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
index 2b30bc3..fd3adab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt
@@ -176,6 +176,30 @@
         assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray())
     }
 
+    @Test
+    fun testGetTaskById_singleTasks() {
+        val task1 = createTaskInfo(id = 1234)
+
+        val taskInfo = GroupedTaskInfo.forFullscreenTasks(task1)
+
+        assertThat(taskInfo.getTaskById(1234)).isEqualTo(task1)
+        assertThat(taskInfo.containsTask(1234)).isTrue()
+    }
+
+    @Test
+    fun testGetTaskById_multipleTasks() {
+        val task1 = createTaskInfo(id = 1)
+        val task2 = createTaskInfo(id = 2)
+        val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50)
+
+        val taskInfo = GroupedTaskInfo.forSplitTasks(task1, task2, splitBounds)
+
+        assertThat(taskInfo.getTaskById(1)).isEqualTo(task1)
+        assertThat(taskInfo.getTaskById(2)).isEqualTo(task2)
+        assertThat(taskInfo.containsTask(1)).isTrue()
+        assertThat(taskInfo.containsTask(2)).isTrue()
+    }
+
     private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
         taskId = id
         token = WindowContainerToken(mock(IWindowContainerToken::class.java))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index dede583..12c3978 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -610,7 +610,7 @@
         mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
 
         GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo);
-        verify(mRecentTasksListener).onTaskMovedToFront(eq(new GroupedTaskInfo[] { runningTask }));
+        verify(mRecentTasksListener).onTaskMovedToFront(eq(runningTask));
     }
 
     @Test
@@ -656,6 +656,35 @@
         assertEquals(splitBounds4, pair2Bounds);
     }
 
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    public void shellTopTaskTracker_onTaskStackChanged_expectNoRecentsChanged() throws Exception {
+        mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+        mRecentTasksControllerReal.onTaskStackChanged();
+        verify(mRecentTasksListener, never()).onRecentTasksChanged();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    public void shellTopTaskTracker_onTaskRemoved_expectNoRecentsChanged() throws Exception {
+        mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+        ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+        mRecentTasksControllerReal.onTaskRemoved(taskInfo);
+        verify(mRecentTasksListener, never()).onRecentTasksChanged();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    public void shellTopTaskTracker_onVisibleTasksChanged() throws Exception {
+        mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+        ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+        mRecentTasksControllerReal.onVisibleTasksChanged(List.of(taskInfo));
+        verify(mRecentTasksListener, never()).onVisibleTasksChanged(any());
+    }
+
     /**
      * Helper to create a task with a given task id.
      */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
index efe4fb1..9919462 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -16,21 +16,36 @@
 
 package com.android.wm.shell.recents
 
-import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.TaskInfo
 import android.app.WindowConfiguration
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
+import android.content.ComponentName
+import android.content.Intent
 import android.os.IBinder
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
 import android.testing.AndroidTestingRunner
 import android.view.SurfaceControl
 import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CHANGE
+import android.view.WindowManager.TRANSIT_CLOSE
+import android.view.WindowManager.TRANSIT_FIRST_CUSTOM
+import android.view.WindowManager.TRANSIT_OPEN
+import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.IWindowContainerToken
 import android.window.TransitionInfo
+import android.window.TransitionInfo.FLAG_MOVED_TO_TOP
 import android.window.WindowContainerToken
 import androidx.test.filters.SmallTest
 import com.android.window.flags.Flags
+import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.TestSyncExecutor
 import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellCommandHandler
 import com.android.wm.shell.sysui.ShellInit
 import com.android.wm.shell.transition.TransitionInfoBuilder
 import com.android.wm.shell.transition.Transitions
@@ -61,7 +76,10 @@
     @JvmField @Rule val setFlagsRule = SetFlagsRule()
 
     @Mock private lateinit var shellInit: ShellInit
-    @Mock lateinit var testExecutor: ShellExecutor
+    @Mock private lateinit var shellTaskOrganizerLazy: Lazy<ShellTaskOrganizer>
+    @Mock private lateinit var shellTaskOrganizer: ShellTaskOrganizer
+    @Mock private lateinit var shellCommandHandler: ShellCommandHandler
+    @Mock private lateinit var testExecutor: ShellExecutor
     @Mock private lateinit var transitionsLazy: Lazy<Transitions>
     @Mock private lateinit var transitions: Transitions
     @Mock private lateinit var mockTransitionBinder: IBinder
@@ -73,24 +91,23 @@
         MockitoAnnotations.initMocks(this)
         shellInit = Mockito.spy(ShellInit(testExecutor))
         whenever(transitionsLazy.get()).thenReturn(transitions)
-        transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit)
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
-            verify(shellInit)
-                .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
-            initRunnableCaptor.value.run()
-        } else {
-            transitionObserver.onInit()
-        }
+        whenever(shellTaskOrganizerLazy.get()).thenReturn(shellTaskOrganizer)
+        transitionObserver = TaskStackTransitionObserver(shellInit, shellTaskOrganizerLazy,
+            shellCommandHandler, transitionsLazy)
+
+        val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+        verify(shellInit)
+            .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+        initRunnableCaptor.value.run()
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun testRegistersObserverAtInit() {
         verify(transitions).registerObserver(same(transitionObserver))
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun taskCreated_freeformWindow_listenerNotified() {
         val listener = TestListener()
@@ -98,11 +115,11 @@
         transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
         val change =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val transitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
 
         callOnTransitionReady(transitionInfo)
         callOnTransitionFinished()
@@ -114,6 +131,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun taskCreated_fullscreenWindow_listenerNotified() {
         val listener = TestListener()
@@ -121,11 +139,11 @@
         transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
         val change =
             createChange(
-                WindowManager.TRANSIT_OPEN,
-                createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+                TRANSIT_OPEN,
+                createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
             )
         val transitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
 
         callOnTransitionReady(transitionInfo)
         callOnTransitionFinished()
@@ -133,10 +151,11 @@
 
         assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(1)
         assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode)
-            .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+            .isEqualTo(WINDOWING_MODE_FULLSCREEN)
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun taskCreated_freeformWindowOnTopOfFreeform_listenerNotified() {
         val listener = TestListener()
@@ -144,7 +163,7 @@
         transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
         val freeformOpenChange =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val freeformReorderChange =
@@ -153,7 +172,7 @@
                 createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val transitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0)
+            TransitionInfoBuilder(TRANSIT_OPEN, 0)
                 .addChange(freeformOpenChange)
                 .addChange(freeformReorderChange)
                 .build()
@@ -169,6 +188,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun transitionMerged_withChange_onlyOpenChangeIsNotified() {
         val listener = TestListener()
@@ -178,11 +198,11 @@
         // Create open transition
         val change =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val transitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
 
         // create change transition to be merged to above transition
         val mergedChange =
@@ -212,6 +232,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun transitionMerged_withOpen_lastOpenChangeIsNotified() {
         val listener = TestListener()
@@ -221,20 +242,20 @@
         // Create open transition
         val change =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val transitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
 
         // create change transition to be merged to above transition
         val mergedChange =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val mergedTransitionInfo =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(mergedChange).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(mergedChange).build()
         val mergedTransition = Mockito.mock(IBinder::class.java)
 
         callOnTransitionReady(transitionInfo)
@@ -250,6 +271,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun taskChange_freeformWindowToFullscreenWindow_listenerNotified() {
         val listener = TestListener()
@@ -257,11 +279,11 @@
         transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
         val freeformState =
             createChange(
-                WindowManager.TRANSIT_OPEN,
+                TRANSIT_OPEN,
                 createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val transitionInfoOpen =
-            TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(freeformState).build()
+            TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(freeformState).build()
         callOnTransitionReady(transitionInfoOpen)
         callOnTransitionFinished()
         executor.flushAll()
@@ -276,7 +298,7 @@
         val fullscreenState =
             createChange(
                 WindowManager.TRANSIT_CHANGE,
-                createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+                createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
             )
         val transitionInfoChange =
             TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0)
@@ -301,6 +323,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun singleTransition_withOpenAndChange_onlyOpenIsNotified() {
         val listener = TestListener()
@@ -310,13 +333,13 @@
         // Creating multiple changes to be fired in a single transition
         val freeformState =
             createChange(
-                mode = WindowManager.TRANSIT_OPEN,
+                mode = TRANSIT_OPEN,
                 taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
             )
         val fullscreenState =
             createChange(
                 mode = WindowManager.TRANSIT_CHANGE,
-                taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+                taskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
             )
 
         val transitionInfoWithChanges =
@@ -336,6 +359,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
     @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
     fun singleTransition_withMultipleChanges_listenerNotified_forEachChange() {
         val listener = TestListener()
@@ -349,7 +373,7 @@
             listOf(
                     WindowConfiguration.WINDOWING_MODE_FREEFORM,
                     WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION,
-                    WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+                    WINDOWING_MODE_FULLSCREEN
                 )
                 .map { change ->
                     createChange(
@@ -376,19 +400,259 @@
         }
     }
 
-    class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
-        var taskInfoOnTaskMovedToFront = ActivityManager.RunningTaskInfo()
-        var taskInfoOnTaskChanged = mutableListOf<ActivityManager.RunningTaskInfo>()
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun openTransition_visibleTasksChanged() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
 
-        override fun onTaskMovedToFrontThroughTransition(
-            taskInfo: ActivityManager.RunningTaskInfo
-        ) {
+        // Model an opening task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        // Assert that the task is reported visible
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+        assertVisibleTasks(listener, listOf(1))
+
+        // Model opening another task
+        val nextOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+                    createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(nextOpeningTransition)
+        // Assert that the visible list from top to bottom is valid (opening, closing)
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+        assertVisibleTasks(listener, listOf(2, 1))
+
+        callOnTransitionFinished()
+        // Assert that after the transition finishes, there is only the opening task remaining
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3)
+        assertVisibleTasks(listener, listOf(2))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun toFrontTransition_visibleTasksChanged() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+        // Model an opening task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        // Assert that the task is reported visible
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+        assertVisibleTasks(listener, listOf(1))
+
+        // Model opening another task
+        val nextOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(nextOpeningTransition)
+        callOnTransitionFinished()
+        // Assert that the visible list from top to bottom is valid
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+        assertVisibleTasks(listener, listOf(2, 1))
+
+        // Model the first task moving to front
+        val toFrontTransition =
+            createTransitionInfo(TRANSIT_TO_FRONT,
+                listOf(
+                    createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN,
+                        FLAG_MOVED_TO_TOP),
+                )
+            )
+
+        callOnTransitionReady(toFrontTransition)
+        callOnTransitionFinished()
+        // Assert that the visible list from top to bottom is valid
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3)
+        assertVisibleTasks(listener, listOf(1, 2))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun closeTransition_visibleTasksChanged() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+        // Model an opening task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+        // Model a closing task
+        val nextOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(nextOpeningTransition)
+        // Assert that the visible list hasn't changed (the close is pending)
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+        callOnTransitionFinished()
+        // Assert that after the transition finishes, there is only the opening task remaining
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+        assertVisibleTasks(listener, listOf())
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun changeTransition_visibleTasksUnchanged() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+        // Model an opening task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+
+        // Model a closing task
+        val nextOpeningTransition =
+            createTransitionInfo(
+                TRANSIT_FIRST_CUSTOM,
+                listOf(
+                    createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(nextOpeningTransition)
+        // Assert that the visible list hasn't changed
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun taskVanished_visibleTasksChanged() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+        // Model an opening task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        // Assert that the task is reported visible
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+        assertVisibleTasks(listener, listOf(1))
+
+        // Trigger task vanished
+        val removedTaskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN)
+        transitionObserver.onTaskVanished(removedTaskInfo)
+
+        // Assert that the visible list is now empty
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+        assertVisibleTasks(listener, listOf())
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+    @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING)
+    fun alwaysOnTop_taskIsTopMostVisible() {
+        val listener = TestListener()
+        val executor = TestSyncExecutor()
+        transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+
+        // Model an opening PIP task
+        val pipOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_PINNED),
+                )
+            )
+
+        callOnTransitionReady(pipOpeningTransition)
+        callOnTransitionFinished()
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1)
+        assertVisibleTasks(listener, listOf(1))
+
+        // Model an opening fullscreen task
+        val firstOpeningTransition =
+            createTransitionInfo(TRANSIT_OPEN,
+                listOf(
+                    createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN),
+                )
+            )
+
+        callOnTransitionReady(firstOpeningTransition)
+        callOnTransitionFinished()
+        assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2)
+        assertVisibleTasks(listener, listOf(1, 2))
+    }
+
+    class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
+        // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is disabled
+        var taskInfoOnTaskMovedToFront = RunningTaskInfo()
+        var taskInfoOnTaskChanged = mutableListOf<RunningTaskInfo>()
+        // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is enabled
+        var visibleTasks = mutableListOf<TaskInfo>()
+        var visibleTasksUpdatedCount = 0
+
+        override fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {
             taskInfoOnTaskMovedToFront = taskInfo
         }
 
-        override fun onTaskChangedThroughTransition(taskInfo: ActivityManager.RunningTaskInfo) {
+        override fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {
             taskInfoOnTaskChanged += taskInfo
         }
+
+        override fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {
+            this.visibleTasks.clear()
+            this.visibleTasks.addAll(visibleTasks)
+            visibleTasksUpdatedCount++
+        }
     }
 
     /** Simulate calling the onTransitionReady() method */
@@ -412,27 +676,64 @@
         transitionObserver.onTransitionMerged(merged, playing)
     }
 
+    /**
+     * Asserts that the listener has the given expected task ids (in order).
+     */
+    private fun assertVisibleTasks(
+        listener: TestListener,
+        expectedVisibleTaskIds: List<Int>
+    ) {
+        assertThat(listener.visibleTasks.size).isEqualTo(expectedVisibleTaskIds.size)
+        expectedVisibleTaskIds.forEachIndexed { index, taskId ->
+            assertThat(listener.visibleTasks[index].taskId).isEqualTo(taskId)
+        }
+    }
+
     companion object {
-        fun createTaskInfo(taskId: Int, windowingMode: Int): ActivityManager.RunningTaskInfo {
-            val taskInfo = ActivityManager.RunningTaskInfo()
+        fun createTaskInfo(taskId: Int, windowingMode: Int): RunningTaskInfo {
+            val taskInfo = RunningTaskInfo()
+            taskInfo.baseIntent = Intent().setComponent(
+                ComponentName(javaClass.packageName, "Test"))
             taskInfo.taskId = taskId
             taskInfo.configuration.windowConfiguration.windowingMode = windowingMode
-
+            if (windowingMode == WINDOWING_MODE_PINNED) {
+                taskInfo.configuration.windowConfiguration.isAlwaysOnTop = true
+            }
             return taskInfo
         }
 
         fun createChange(
             mode: Int,
-            taskInfo: ActivityManager.RunningTaskInfo
+            taskInfo: RunningTaskInfo,
+            flags: Int = 0,
         ): TransitionInfo.Change {
             val change =
                 TransitionInfo.Change(
                     WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)),
                     Mockito.mock(SurfaceControl::class.java)
                 )
+            change.flags = flags
             change.mode = mode
             change.taskInfo = taskInfo
             return change
         }
+
+        fun createChange(
+            mode: Int,
+            taskId: Int,
+            windowingMode: Int,
+            flags: Int = 0,
+        ): TransitionInfo.Change {
+            return createChange(mode, createTaskInfo(taskId, windowingMode), flags)
+        }
+
+        fun createTransitionInfo(
+            transitionType: Int,
+            changes: List<TransitionInfo.Change>
+        ): TransitionInfo {
+            return TransitionInfoBuilder(transitionType, 0)
+                .apply { changes.forEach { c -> this@apply.addChange(c) } }
+                .build()
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index c36b88e..71af97e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -43,6 +43,7 @@
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
+import com.android.wm.shell.TestSyncExecutor;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.sysui.ShellInit;
@@ -475,27 +476,6 @@
         }
     }
 
-    private static class TestSyncExecutor implements ShellExecutor {
-        @Override
-        public void execute(Runnable runnable) {
-            runnable.run();
-        }
-
-        @Override
-        public void executeDelayed(Runnable runnable, long delayMillis) {
-            runnable.run();
-        }
-
-        @Override
-        public void removeCallbacks(Runnable runnable) {
-        }
-
-        @Override
-        public boolean hasCallback(Runnable runnable) {
-            return false;
-        }
-    }
-
     private TransitionInfo createUnfoldTransitionInfo() {
         TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
         TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
new file mode 100644
index 0000000..3e26ee0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.util
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.IBinder
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.view.WindowManager.TRANSIT_NONE
+import android.view.WindowManager.TransitionFlags
+import android.view.WindowManager.TransitionType
+import android.window.IWindowContainerToken
+import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
+import android.window.TransitionInfo.ChangeFlags
+import android.window.TransitionInfo.FLAG_NONE
+import android.window.TransitionInfo.TransitionMode
+import android.window.WindowContainerToken
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
+import com.android.wm.shell.transition.Transitions.TransitionObserver
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+
+@DslMarker
+annotation class TransitionObserverTagMarker
+
+/**
+ * Abstraction for all the phases of the [TransitionObserver] test.
+ */
+interface TransitionObserverTestStep
+
+/**
+ * Encapsulates the values for the [TransitionObserver#onTransitionReady] input parameters.
+ */
+class TransitionObserverTransitionReadyInput(
+    val transition: IBinder,
+    val info: TransitionInfo,
+    val startTransaction: Transaction,
+    val finishTransaction: Transaction
+)
+
+@TransitionObserverTagMarker
+class TransitionObserverTestContext : TransitionObserverTestStep {
+
+    lateinit var transitionObserver: TransitionObserver
+    lateinit var transitionReadyInput: TransitionObserverTransitionReadyInput
+
+    fun inputBuilder(builderInput: TransitionObserverInputBuilder.() -> Unit) {
+        val inputFactoryObj = TransitionObserverInputBuilder()
+        inputFactoryObj.builderInput()
+        transitionReadyInput = inputFactoryObj.build()
+    }
+
+    fun validateOutput(
+        validate:
+        TransitionObserverResultValidation.() -> Unit
+    ) {
+        val validateObj = TransitionObserverResultValidation()
+        invokeObservable()
+        validateObj.validate()
+    }
+
+    fun invokeObservable() {
+        transitionObserver.onTransitionReady(
+            transitionReadyInput.transition,
+            transitionReadyInput.info,
+            transitionReadyInput.startTransaction,
+            transitionReadyInput.finishTransaction
+        )
+    }
+}
+
+/**
+ * Phase responsible for the input parameters for [TransitionObserver].
+ */
+class TransitionObserverInputBuilder : TransitionObserverTestStep {
+
+    private val transition = Mockito.mock(IBinder::class.java)
+    private var transitionInfo: TransitionInfo? = null
+    private val startTransaction = Mockito.mock(Transaction::class.java)
+    private val finishTransaction = Mockito.mock(Transaction::class.java)
+
+    fun buildTransitionInfo(
+        @TransitionType type: Int = TRANSIT_NONE,
+        @TransitionFlags flags: Int = 0
+    ) {
+        transitionInfo = TransitionInfo(type, flags)
+        spyOn(transitionInfo)
+    }
+
+    fun addChange(
+        token: WindowContainerToken? = mock(),
+        leash: SurfaceControl = mock(),
+        @TransitionMode changeMode: Int = TRANSIT_NONE,
+        parentToken: WindowContainerToken? = null,
+        changeTaskInfo: RunningTaskInfo? = null,
+        @ChangeFlags changeFlags: Int = FLAG_NONE
+    ) = addChange(Change(token, leash).apply {
+        mode = changeMode
+        parent = parentToken
+        taskInfo = changeTaskInfo
+        flags = changeFlags
+    })
+
+    fun createChange(
+        token: WindowContainerToken? = mock(),
+        leash: SurfaceControl = mock(),
+        @TransitionMode changeMode: Int = TRANSIT_NONE,
+        parentToken: WindowContainerToken? = null,
+        changeTaskInfo: RunningTaskInfo? = null,
+        @ChangeFlags changeFlags: Int = FLAG_NONE
+    ) = Change(token, leash).apply {
+        mode = changeMode
+        parent = parentToken
+        taskInfo = changeTaskInfo
+        flags = changeFlags
+    }
+
+    fun addChange(change: Change) {
+        transitionInfo!!.addChange(change)
+    }
+
+    fun createTaskInfo(id: Int = 0, windowingMode: Int = WINDOWING_MODE_FREEFORM) =
+        RunningTaskInfo().apply {
+            taskId = id
+            displayId = DEFAULT_DISPLAY
+            configuration.windowConfiguration.windowingMode = windowingMode
+            token = WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java))
+            baseIntent = Intent().apply {
+                component = ComponentName("package", "component.name")
+            }
+        }
+
+    fun build(): TransitionObserverTransitionReadyInput = TransitionObserverTransitionReadyInput(
+        transition = transition,
+        info = transitionInfo!!,
+        startTransaction = startTransaction,
+        finishTransaction = finishTransaction
+    )
+}
+
+/**
+ * Phase responsible for the execution of validation methods.
+ */
+class TransitionObserverResultValidation : TransitionObserverTestStep
+
+/**
+ * Allows to run a test about a specific [TransitionObserver] passing the specific
+ * implementation and input value as parameters for the [TransitionObserver#onTransitionReady]
+ * method.
+ * @param observerFactory    The Factory for the TransitionObserver
+ * @param inputFactory      The Builder for the onTransitionReady input parameters
+ * @param init  The test code itself.
+ */
+fun executeTransitionObserverTest(
+    observerFactory: () -> TransitionObserver,
+    init: TransitionObserverTestContext.() -> Unit
+): TransitionObserverTestContext {
+    val testContext = TransitionObserverTestContext().apply {
+        transitionObserver = observerFactory()
+    }
+    testContext.init()
+    return testContext
+}
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 be664f8..ef9b30c 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
@@ -63,7 +63,6 @@
 import android.view.View
 import android.view.ViewRootImpl
 import android.view.WindowInsets.Type.statusBars
-import android.widget.Toast
 import android.window.WindowContainerTransaction
 import android.window.WindowContainerTransaction.HierarchyOp
 import androidx.test.filters.SmallTest
@@ -186,7 +185,6 @@
     @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser
     @Mock private lateinit var mockUserHandle: UserHandle
     @Mock private lateinit var mockAssistContentRequester: AssistContentRequester
-    @Mock private lateinit var mockToast: Toast
     private val bgExecutor = TestShellExecutor()
     @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper
     @Mock private lateinit var mockTasksLimiter: DesktopTasksLimiter
@@ -226,7 +224,6 @@
                 .strictness(Strictness.LENIENT)
                 .spyStatic(DesktopModeStatus::class.java)
                 .spyStatic(DragPositioningCallbackUtility::class.java)
-                .spyStatic(Toast::class.java)
                 .startMocking()
         doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) }
 
@@ -290,8 +287,6 @@
         )
             .thenReturn(mockTaskPositioner)
 
-        doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }
-
         // InputChannel cannot be mocked because it passes to InputEventReceiver.
         val inputChannels = InputChannel.openInputChannelPair(TAG)
         inputChannels.first().dispose()
@@ -640,7 +635,6 @@
 
     @Test
     fun testOnDecorSnappedLeft_snapResizes() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -648,19 +642,15 @@
             onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
         )
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onLeftSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.LEFT),
             eq(ResizeTrigger.SNAP_LEFT_MENU),
             eq(null),
             eq(decor)
         )
-        assertEquals(taskSurfaceCaptor.firstValue, decor.mTaskSurface)
     }
 
     @Test
@@ -681,7 +671,6 @@
     @Test
     @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
     fun testOnSnapResizeLeft_nonResizable_decorSnappedLeft() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onLeftSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -689,19 +678,15 @@
             onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor
         ).also { it.mTaskInfo.isResizeable = false }
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onLeftSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.LEFT),
             eq(ResizeTrigger.SNAP_LEFT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -723,12 +708,10 @@
                 eq(null),
                 eq(decor),
             )
-        verify(mockToast).show()
     }
 
     @Test
     fun testOnDecorSnappedRight_snapResizes() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -736,19 +719,15 @@
             onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
         )
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onRightSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.RIGHT),
             eq(ResizeTrigger.SNAP_RIGHT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -769,7 +748,6 @@
     @Test
     @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING)
     fun testOnSnapResizeRight_nonResizable_decorSnappedRight() {
-        val taskSurfaceCaptor = argumentCaptor<SurfaceControl>()
         val onRightSnapClickListenerCaptor = forClass(Function0::class.java)
                 as ArgumentCaptor<Function0<Unit>>
         val decor = createOpenTaskDecoration(
@@ -777,19 +755,15 @@
             onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor
         ).also { it.mTaskInfo.isResizeable = false }
 
-        val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds
         onRightSnapClickListenerCaptor.value.invoke()
 
-        verify(mockDesktopTasksController).snapToHalfScreen(
+        verify(mockDesktopTasksController).handleInstantSnapResizingTask(
             eq(decor.mTaskInfo),
-            taskSurfaceCaptor.capture(),
-            eq(currentBounds),
             eq(SnapPosition.RIGHT),
             eq(ResizeTrigger.SNAP_RIGHT_MENU),
             eq(null),
             eq(decor),
         )
-        assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue)
     }
 
     @Test
@@ -811,7 +785,6 @@
                 eq(null),
                 eq(decor),
         )
-        verify(mockToast).show()
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 1d2d0f0..f653622 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -30,6 +30,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
 import static com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.CLOSE_MAXIMIZE_MENU_DELAY_MS;
+import static com.android.wm.shell.windowdecor.WindowDecoration.INVALID_CORNER_RADIUS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -219,7 +220,7 @@
     @Captor
     private ArgumentCaptor<Runnable> mCloseMaxMenuRunnable;
 
-    private final InsetsState mInsetsState = new InsetsState();
+    private final InsetsState mInsetsState = createInsetsState(statusBars(), /* visible= */true);
     private SurfaceControl.Transaction mMockTransaction;
     private StaticMockitoSession mMockitoSession;
     private TestableContext mTestableContext;
@@ -312,8 +313,9 @@
     }
 
     @Test
-    public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersAreEnabled() {
+    public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
         fillRoundedCornersResources(/* fillValue= */ 30);
         RelayoutParams relayoutParams = new RelayoutParams();
 
@@ -334,6 +336,29 @@
     }
 
     @Test
+    public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        fillRoundedCornersResources(/* fillValue= */ 30);
+        RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false,
+                /* isStatusBarVisible */ true,
+                /* isKeyguardVisibleAndOccluded */ false,
+                /* inFullImmersiveMode */ false,
+                new InsetsState(),
+                /* hasGlobalFocus= */ true,
+                mExclusionRegion);
+
+        assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS);
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
     public void updateRelayoutParams_appHeader_usesTaskDensity() {
         final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
@@ -1408,8 +1433,6 @@
     public void notifyCaptionStateChanged_flagDisabled_doNoNotify() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
@@ -1423,8 +1446,6 @@
     public void notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1444,8 +1465,6 @@
     public void notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         when(mMockAppHeaderViewHolder.getAppChipLocationInWindow()).thenReturn(
                 new Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
@@ -1473,8 +1492,6 @@
     public void notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ false);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1493,8 +1510,6 @@
     public void notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
@@ -1518,8 +1533,6 @@
     public void notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed() {
         when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true);
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        when(mMockDisplayController.getInsetsState(taskInfo.displayId))
-                .thenReturn(createInsetsState(statusBars(), /* visible= */true));
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass(
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index fcb7efc..e2db2c9 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -355,6 +355,7 @@
         "jni/AnimatedImageDrawable.cpp",
         "jni/Bitmap.cpp",
         "jni/BitmapRegionDecoder.cpp",
+        "jni/RuntimeXfermode.cpp",
         "jni/BufferUtils.cpp",
         "jni/HardwareBufferHelpers.cpp",
         "jni/BitmapFactory.cpp",
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7c15086..7f5ca44 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -622,18 +622,13 @@
     auto colorSpace = info.colorSpace();
     // If we don't have a colorspace, we can't apply a gainmap
     if (!colorSpace) return false;
-    skcms_TransferFunction tfn;
-    colorSpace->transferFn(&tfn);
 
-    auto transferType = skcms_TransferFunction_getType(&tfn);
-    switch (transferType) {
-        case skcms_TFType_HLGish:
-        case skcms_TFType_HLGinvish:
-        case skcms_TFType_PQish:
-            return true;
-        case skcms_TFType_Invalid:
-        case skcms_TFType_sRGBish:
-            return false;
+    const float targetRatio = uirenderer::getTargetHdrSdrRatio(colorSpace);
+
+    if (bitmap.gainmap()->info.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+        return targetRatio < bitmap.gainmap()->info.fDisplayRatioHdr;
+    } else {
+        return targetRatio > bitmap.gainmap()->info.fDisplayRatioSdr;
     }
 }
 
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 15b2bac..56de568 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -28,6 +28,7 @@
 extern int register_android_graphics_Bitmap(JNIEnv*);
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
 extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
+extern int register_android_graphics_RuntimeXfermode(JNIEnv*);
 extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
 extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
@@ -107,6 +108,7 @@
             REG_JNI(register_android_graphics_Bitmap),
             REG_JNI(register_android_graphics_BitmapFactory),
             REG_JNI(register_android_graphics_BitmapRegionDecoder),
+            REG_JNI(register_android_graphics_RuntimeXfermode),
             REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
             REG_JNI(register_android_graphics_Camera),
             REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp
index eac0360..18b77bc 100644
--- a/libs/hwui/effects/GainmapRenderer.cpp
+++ b/libs/hwui/effects/GainmapRenderer.cpp
@@ -73,7 +73,9 @@
 #ifdef __ANDROID__
     auto destColorspace = c->imageInfo().refColorSpace();
     float targetSdrHdrRatio = getTargetHdrSdrRatio(destColorspace.get());
-    if (targetSdrHdrRatio > 1.f && gainmapImage) {
+    const bool baseImageHdr = gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR;
+    if (gainmapImage && ((baseImageHdr && targetSdrHdrRatio < gainmapInfo.fDisplayRatioHdr) ||
+                         (!baseImageHdr && targetSdrHdrRatio > gainmapInfo.fDisplayRatioSdr))) {
         SkPaint gainmapPaint = *paint;
         float sX = gainmapImage->width() / (float)image->width();
         float sY = gainmapImage->height() / (float)image->height();
@@ -183,7 +185,10 @@
                 baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB();
 
         // Determine the color space in which the gainmap math is to be applied.
-        sk_sp<SkColorSpace> gainmapMathColorSpace = baseColorSpace->makeLinearGamma();
+        sk_sp<SkColorSpace> gainmapMathColorSpace =
+                mGainmapInfo.fGainmapMathColorSpace
+                        ? mGainmapInfo.fGainmapMathColorSpace->makeLinearGamma()
+                        : baseColorSpace->makeLinearGamma();
 
         // Create a color filter to transform from the base image's color space to the color space
         // in which the gainmap is to be applied.
@@ -266,6 +271,10 @@
                     W = 1.f;
                 }
             }
+
+            if (mGainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) {
+                W -= 1.f;
+            }
             mBuilder.uniform("W") = W;
             uniforms = mBuilder.uniforms();
         }
@@ -317,4 +326,4 @@
 
 #endif  // __ANDROID__
 
-}  // namespace android::uirenderer
\ No newline at end of file
+}  // namespace android::uirenderer
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index da23792..a7d855d 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -906,6 +906,13 @@
         paint->setBlendMode(mode);
     }
 
+    static void setRuntimeXfermode(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle,
+                                   jlong xfermodeHandle) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        SkBlender* blender = reinterpret_cast<SkBlender*>(xfermodeHandle);
+        paint->setBlender(sk_ref_sp(blender));
+    }
+
     static jlong setPathEffect(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong effectHandle) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         SkPathEffect* effect  = reinterpret_cast<SkPathEffect*>(effectHandle);
@@ -1233,6 +1240,7 @@
         {"nSetShader", "(JJ)J", (void*)PaintGlue::setShader},
         {"nSetColorFilter", "(JJ)J", (void*)PaintGlue::setColorFilter},
         {"nSetXfermode", "(JI)V", (void*)PaintGlue::setXfermode},
+        {"nSetXfermode", "(JJ)V", (void*)PaintGlue::setRuntimeXfermode},
         {"nSetPathEffect", "(JJ)J", (void*)PaintGlue::setPathEffect},
         {"nSetMaskFilter", "(JJ)J", (void*)PaintGlue::setMaskFilter},
         {"nSetTypeface", "(JJ)V", (void*)PaintGlue::setTypeface},
diff --git a/libs/hwui/jni/RuntimeEffectUtils.cpp b/libs/hwui/jni/RuntimeEffectUtils.cpp
index 46db863..ad0e540 100644
--- a/libs/hwui/jni/RuntimeEffectUtils.cpp
+++ b/libs/hwui/jni/RuntimeEffectUtils.cpp
@@ -90,7 +90,7 @@
                  SkFlattenable* childEffect) {
     SkRuntimeShaderBuilder::BuilderChild builderChild = builder->child(childName);
     if (builderChild.fChild == nullptr) {
-        ThrowIAEFmt(env, "unable to find shader named %s", childName);
+        ThrowIAEFmt(env, "unable to find child named %s", childName);
         return;
     }
 
diff --git a/libs/hwui/jni/RuntimeXfermode.cpp b/libs/hwui/jni/RuntimeXfermode.cpp
new file mode 100644
index 0000000..c1c8964
--- /dev/null
+++ b/libs/hwui/jni/RuntimeXfermode.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include "GraphicsJNI.h"
+#include "RuntimeEffectUtils.h"
+#include "SkBlender.h"
+
+using namespace android::uirenderer;
+
+static void SkRuntimeEffectBuilder_delete(SkRuntimeEffectBuilder* builder) {
+    delete builder;
+}
+
+static jlong RuntimeXfermode_getNativeFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeEffectBuilder_delete));
+}
+
+static jlong RuntimeXfermode_createBuilder(JNIEnv* env, jobject, jstring sksl) {
+    ScopedUtfChars strSksl(env, sksl);
+    auto result =
+            SkRuntimeEffect::MakeForBlender(SkString(strSksl.c_str()), SkRuntimeEffect::Options{});
+    if (result.effect.get() == nullptr) {
+        doThrowIAE(env, result.errorText.c_str());
+        return 0;
+    }
+    return reinterpret_cast<jlong>(new SkRuntimeEffectBuilder(std::move(result.effect)));
+}
+
+static jlong RuntimeXfermode_create(JNIEnv* env, jobject, jlong builderPtr) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    sk_sp<SkBlender> blender = builder->makeBlender();
+    if (!blender) {
+        doThrowIAE(env);
+    }
+    return reinterpret_cast<jlong>(blender.release());
+}
+
+static void RuntimeXfermode_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong builderPtr,
+                                                     jstring uniformName, jfloatArray uniforms,
+                                                     jboolean isColor) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, uniformName);
+    AutoJavaFloatArray autoValues(env, uniforms, 0, kRO_JNIAccess);
+    UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
+}
+
+static void RuntimeXfermode_updateFloatUniforms(JNIEnv* env, jobject, jlong builderPtr,
+                                                jstring uniformName, jfloat value1, jfloat value2,
+                                                jfloat value3, jfloat value4, jint count) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, uniformName);
+    const float values[4] = {value1, value2, value3, value4};
+    UpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
+}
+
+static void RuntimeXfermode_updateIntArrayUniforms(JNIEnv* env, jobject, jlong builderPtr,
+                                                   jstring uniformName, jintArray uniforms) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, uniformName);
+    AutoJavaIntArray autoValues(env, uniforms, 0);
+    UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
+}
+
+static void RuntimeXfermode_updateIntUniforms(JNIEnv* env, jobject, jlong builderPtr,
+                                              jstring uniformName, jint value1, jint value2,
+                                              jint value3, jint value4, jint count) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, uniformName);
+    const int values[4] = {value1, value2, value3, value4};
+    UpdateIntUniforms(env, builder, name.c_str(), values, count);
+}
+
+static void RuntimeXfermode_updateChild(JNIEnv* env, jobject, jlong builderPtr, jstring childName,
+                                        jlong childPtr) {
+    auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr);
+    ScopedUtfChars name(env, childName);
+    auto* child = reinterpret_cast<SkFlattenable*>(childPtr);
+    if (child) {
+        UpdateChild(env, builder, name.c_str(), child);
+    }
+}
+
+static const JNINativeMethod gRuntimeXfermodeMethods[] = {
+        {"nativeGetFinalizer", "()J", (void*)RuntimeXfermode_getNativeFinalizer},
+        {"nativeCreateBlenderBuilder", "(Ljava/lang/String;)J",
+         (void*)RuntimeXfermode_createBuilder},
+        {"nativeCreateNativeInstance", "(J)J", (void*)RuntimeXfermode_create},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
+         (void*)RuntimeXfermode_updateFloatArrayUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V",
+         (void*)RuntimeXfermode_updateFloatUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V",
+         (void*)RuntimeXfermode_updateIntArrayUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
+         (void*)RuntimeXfermode_updateIntUniforms},
+        {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeXfermode_updateChild},
+};
+
+int register_android_graphics_RuntimeXfermode(JNIEnv* env) {
+    android::RegisterMethodsOrDie(env, "android/graphics/RuntimeXfermode", gRuntimeXfermodeMethods,
+                                  NELEM(gRuntimeXfermodeMethods));
+
+    return 0;
+}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 2a057e7..018c2b13 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -2,6 +2,7 @@
 
 #include "Gainmap.h"
 #include "GraphicsJNI.h"
+#include "RuntimeEffectUtils.h"
 #include "SkBitmap.h"
 #include "SkBlendMode.h"
 #include "SkColor.h"
@@ -280,50 +281,6 @@
     return ret;
 }
 
-static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
-    switch (type) {
-        case SkRuntimeEffect::Uniform::Type::kFloat:
-        case SkRuntimeEffect::Uniform::Type::kFloat2:
-        case SkRuntimeEffect::Uniform::Type::kFloat3:
-        case SkRuntimeEffect::Uniform::Type::kFloat4:
-        case SkRuntimeEffect::Uniform::Type::kFloat2x2:
-        case SkRuntimeEffect::Uniform::Type::kFloat3x3:
-        case SkRuntimeEffect::Uniform::Type::kFloat4x4:
-            return false;
-        case SkRuntimeEffect::Uniform::Type::kInt:
-        case SkRuntimeEffect::Uniform::Type::kInt2:
-        case SkRuntimeEffect::Uniform::Type::kInt3:
-        case SkRuntimeEffect::Uniform::Type::kInt4:
-            return true;
-    }
-}
-
-static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder,
-                                const char* uniformName, const float values[], int count,
-                                bool isColor) {
-    SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
-    if (uniform.fVar == nullptr) {
-        ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
-    } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
-        if (isColor) {
-            jniThrowExceptionFmt(
-                    env, "java/lang/IllegalArgumentException",
-                    "attempting to set a color uniform using the non-color specific APIs: %s %x",
-                    uniformName, uniform.fVar->flags);
-        } else {
-            ThrowIAEFmt(env,
-                        "attempting to set a non-color uniform using the setColorUniform APIs: %s",
-                        uniformName);
-        }
-    } else if (isIntUniformType(uniform.fVar->type)) {
-        ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
-                    uniformName);
-    } else if (!uniform.set<float>(values, count)) {
-        ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
-                    uniform.fVar->sizeInBytes(), sizeof(float) * count);
-    }
-}
-
 static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
                                               jstring jUniformName, jfloat value1, jfloat value2,
                                               jfloat value3, jfloat value4, jint count) {
@@ -342,20 +299,6 @@
     UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor);
 }
 
-static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName,
-                              const int values[], int count) {
-    SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName);
-    if (uniform.fVar == nullptr) {
-        ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
-    } else if (!isIntUniformType(uniform.fVar->type)) {
-        ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
-                    uniformName);
-    } else if (!uniform.set<int>(values, count)) {
-        ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
-                    uniform.fVar->sizeInBytes(), sizeof(float) * count);
-    }
-}
-
 static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder,
                                             jstring jUniformName, jint value1, jint value2,
                                             jint value3, jint value4, jint count) {
@@ -388,6 +331,15 @@
     builder->child(name.c_str()) = sk_ref_sp(shader);
 }
 
+static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder,
+                                      jstring jUniformName, jlong childHandle) {
+    SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
+    ScopedUtfChars name(env, jUniformName);
+    auto* childEffect = reinterpret_cast<SkFlattenable*>(childHandle);
+
+    UpdateChild(env, builder, name.c_str(), childEffect);
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gShaderMethods[] = {
@@ -428,6 +380,7 @@
         {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V",
          (void*)RuntimeShader_updateIntUniforms},
         {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader},
+        {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateChild},
 };
 
 int register_android_graphics_Shader(JNIEnv* env)
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 2da8eec..b41f40f 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE;
+import static android.media.audio.Flags.FLAG_SPEAKER_LAYOUT_API;
 
 import android.Manifest;
 import android.annotation.FlaggedApi;
@@ -548,6 +549,19 @@
     }
 
     /**
+     * @return A ChannelMask representing the physical output speaker layout of the device.
+     *
+     * The layout channel mask only indicates which speaker channels are present, the
+     * physical layout of the speakers should be informed by a standard for multi-channel
+     * sound playback systems, such as ITU-R BS.2051.
+     * @see AudioFormat
+     */
+    @FlaggedApi(FLAG_SPEAKER_LAYOUT_API)
+    public int getSpeakerLayoutChannelMask() {
+        return mPort.speakerLayoutChannelMask();
+    }
+
+    /**
      * @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT},
      * {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device.
      * <code>ENCODING_PCM_FLOAT</code> indicates the device supports more
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index ab5c54b..f5913c7 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -60,8 +60,27 @@
                 /* encapsulationMetadataTypes= */ null);
     }
 
+    /** @hide */
+    // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further
+    // down the stack.
+    @VisibleForTesting
+    public static AudioDevicePort createForTesting(int speakerLayoutChannelMask) {
+        return new AudioDevicePort(
+                new AudioHandle(/* id= */ 0),
+                /* name= */ "testAudioDevicePort",
+                /* profiles= */ null,
+                /* gains= */ null,
+                /* type= */ AudioManager.DEVICE_OUT_SPEAKER,
+                /* address= */ "testAddress",
+                /* speakerLayoutChannelMask= */ speakerLayoutChannelMask,
+                /* encapsulationModes= */ null,
+                /* encapsulationMetadataTypes= */ null,
+                /* descriptors= */ null);
+    }
+
     private final int mType;
     private final String mAddress;
+    private final int mSpeakerLayoutChannelMask;
     private final int[] mEncapsulationModes;
     private final int[] mEncapsulationMetadataTypes;
 
@@ -76,12 +95,20 @@
              deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
         mType = type;
         mAddress = address;
+        mSpeakerLayoutChannelMask = AudioFormat.CHANNEL_INVALID;
         mEncapsulationModes = encapsulationModes;
         mEncapsulationMetadataTypes = encapsulationMetadataTypes;
     }
 
-    AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles,
-            AudioGain[] gains, int type, String address, int[] encapsulationModes,
+    AudioDevicePort(
+            AudioHandle handle,
+            String deviceName,
+            List<AudioProfile> profiles,
+            AudioGain[] gains,
+            int type,
+            String address,
+            int speakerLayoutChannelMask,
+            int[] encapsulationModes,
             @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes,
             List<AudioDescriptor> descriptors) {
         super(handle,
@@ -89,6 +116,7 @@
                 deviceName, profiles, gains, descriptors);
         mType = type;
         mAddress = address;
+        mSpeakerLayoutChannelMask = speakerLayoutChannelMask;
         mEncapsulationModes = encapsulationModes;
         mEncapsulationMetadataTypes = encapsulationMetadataTypes;
     }
@@ -119,6 +147,16 @@
         return mAddress;
     }
 
+    /** Get the channel mask representing the physical output speaker layout of the device.
+     *
+     * The layout channel mask only indicates which speaker channels are present, the
+     * physical layout of the speakers should be informed by a standard for multi-channel
+     * sound playback systems, such as ITU-R BS.2051.
+    */
+    public int speakerLayoutChannelMask() {
+        return mSpeakerLayoutChannelMask;
+    }
+
     /**
      * Get supported encapsulation modes.
      */
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 3cd5f52..da50f2c 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -19,6 +19,7 @@
 import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_ALL;
 import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE;
 import static android.media.audio.Flags.FLAG_MUTED_BY_PORT_VOLUME_API;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -39,6 +40,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -461,8 +464,12 @@
 
     /**
      * Returns information about the {@link AudioDeviceInfo} used for this playback.
-     * @return the audio playback device or null if the device is not available at the time of query
+     * @return the audio playback device or null if the device is not available at the time of
+     * query.
+     * @deprecated this information was never populated
      */
+    @Deprecated
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
     public @Nullable AudioDeviceInfo getAudioDeviceInfo() {
         final int deviceId;
         synchronized (mUpdateablePropLock) {
@@ -476,6 +483,23 @@
 
     /**
      * @hide
+     * Returns information about the List of {@link AudioDeviceInfo} used for this playback.
+     * @return the audio playback devices
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public @NonNull List<AudioDeviceInfo> getAudioDeviceInfos() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getAudioDeviceInfo();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
+     * @hide
      * Return the audio session ID associated with this player.
      * See {@link AudioManager#generateAudioSessionId()}.
      * @return an audio session ID
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 80e5719..9394941 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,8 +20,10 @@
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
 import static android.content.Context.DEVICE_ID_DEFAULT;
 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -1920,6 +1922,23 @@
     }
 
     /**
+     * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+     * AudioRecord.
+     * Note: The query is only valid if the AudioRecord is currently playing. If it is not,
+     * <code>getRoutedDevices()</code> will return an empty list.
+     */
+    @Override
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
      * Must match the native definition in frameworks/av/service/audioflinger/Audioflinger.h.
      */
     private static final long MAX_SHARED_AUDIO_HISTORY_MS = 5000;
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
index 26fa631..22aa9a0 100644
--- a/media/java/android/media/AudioRouting.java
+++ b/media/java/android/media/AudioRouting.java
@@ -16,9 +16,16 @@
 
 package android.media;
 
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.os.Handler;
 import android.os.Looper;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * AudioRouting defines an interface for controlling routing and routing notifications in
  * AudioTrack and AudioRecord objects.
@@ -49,6 +56,22 @@
     public AudioDeviceInfo getRoutedDevice();
 
     /**
+     * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+     * AudioTrack/AudioRecord.
+     * Note: The query is only valid if the AudioTrack/AudioRecord is currently playing.
+     * If it is not, <code>getRoutedDevices()</code> will return an empty List.
+     */
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    default @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return new ArrayList<AudioDeviceInfo>();
+    }
+
+    /**
      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
      * changes on this AudioTrack/AudioRecord.
      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 03cd535..93a1831 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -17,8 +17,10 @@
 package android.media;
 
 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -54,7 +56,9 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.NioUtils;
+import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -3783,6 +3787,8 @@
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
      * Note: The query is only valid if the AudioTrack is currently playing. If it is not,
      * <code>getRoutedDevice()</code> will return null.
+     * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and
+     * speaker on a phone), so prefer using {@link #getRoutedDevices}.
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
@@ -3793,6 +3799,23 @@
         return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
     }
 
+    /**
+     * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+     * AudioTrack.
+     * Note: The query is only valid if the AudioTrack is currently playing. If it is not,
+     * <code>getRoutedDevices()</code> will return an empty list.
+     */
+    @Override
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return audioDeviceInfos;
+    }
+
     private void tryToDisableNativeRoutingCallback() {
         synchronized (mRoutingChangeListeners) {
             if (mEnableSelfRoutingMonitor) {
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 9325999..0a79f41 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -1157,7 +1157,11 @@
         @Override
         public void setFence(@NonNull SyncFence fence) throws IOException {
             throwISEIfImageIsInvalid();
-            nativeSetFenceFd(fence.getFdDup().detachFd());
+            if (fence.isValid()) {
+                nativeSetFenceFd(fence.getFdDup().detachFd());
+            } else {
+                nativeSetFenceFd(-1);
+            }
         }
 
         @Override
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 3f9126a..1ecba31 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -16,10 +16,9 @@
 
 package android.media;
 
+import static android.media.tv.flags.Flags.FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY;
 import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN;
 
-import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY;
-
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -996,7 +995,7 @@
      * @param niceValue the nice value.
      * @hide
      */
-    @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY)
+    @FlaggedApi(FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY)
     @SystemApi
     @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
     public boolean updateResourcePriority(int priority, int niceValue) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 2ae89d3..82e9503 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import static android.media.codec.Flags.FLAG_CODEC_AVAILABILITY;
 import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
 import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
 import static android.media.codec.Flags.FLAG_SUBSESSION_METRICS;
@@ -29,6 +30,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
@@ -1843,6 +1845,12 @@
      */
     private static final int CB_METRICS_FLUSHED = 8;
 
+    /**
+     * Callback ID to notify the change in resource requirement
+     * for the codec component.
+     */
+    private static final int CB_REQUIRED_RESOURCES_CHANGE = 9;
+
     private class EventHandler extends Handler {
         private MediaCodec mCodec;
 
@@ -2017,13 +2025,19 @@
 
                 case CB_METRICS_FLUSHED:
                 {
-
                     if (GetFlag(() -> android.media.codec.Flags.subsessionMetrics())) {
                         mCallback.onMetricsFlushed(mCodec, (PersistableBundle)msg.obj);
                     }
                     break;
                 }
 
+                case CB_REQUIRED_RESOURCES_CHANGE: {
+                    if (android.media.codec.Flags.codecAvailability()) {
+                        mCallback.onRequiredResourcesChanged(mCodec);
+                    }
+                    break;
+                }
+
                 default:
                 {
                     break;
@@ -2302,6 +2316,70 @@
     }
 
     /**
+     * @hide
+     * Abstraction for the Global Codec resources.
+     * This encapsulates all the available codec resources on the device.
+     *
+     * To be able to enforce and test the implementation of codec availability hal APIs,
+     * globally available codec resources are exposed only as TestApi.
+     * This will be tracked and verified through cts.
+     */
+    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+    @TestApi
+    public static final class GlobalResourceInfo {
+        /**
+         * Identifier for the Resource type.
+         */
+        String mName;
+        /**
+         * Total count/capacity of resources of this type.
+         */
+        long mCapacity;
+        /**
+         * Available count of this resource type.
+         */
+        long mAvailable;
+
+        @NonNull
+        public String getName() {
+            return mName;
+        }
+
+        public long getCapacity() {
+            return mCapacity;
+        }
+
+        public long getAvailable() {
+            return mAvailable;
+        }
+    };
+
+    /**
+     * @hide
+     * Get a list of globally available codec resources.
+     *
+     * To be able to enforce and test the implementation of codec availability hal APIs,
+     * it is exposed only as TestApi.
+     * This will be tracked and verified through cts.
+     *
+     * This returns a {@link java.util.List} list of codec resources.
+     * For every {@link GlobalResourceInfo} in the list, it encapsulates the
+     * information about each resources available globaly on device.
+     *
+     * @return A list of available device codec resources; an empty list if no
+     *         device codec resources are available.
+     * @throws UnsupportedOperationException if not implemented.
+     */
+    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+    @TestApi
+    public static @NonNull List<GlobalResourceInfo> getGloballyAvailableResources() {
+        return native_getGloballyAvailableResources();
+    }
+
+    @NonNull
+    private static native List<GlobalResourceInfo> native_getGloballyAvailableResources();
+
+    /**
      * Configures a component.
      *
      * @param format The format of the input data (decoder) or the desired
@@ -2443,6 +2521,73 @@
     }
 
     /**
+     * @hide
+     * Abstraction for the resources associated with a codec instance.
+     * This encapsulates the required codec resources for a configured codec instance.
+     *
+     * To be able to enforce and test the implementation of codec availability hal APIs,
+     * required codec resources are exposed only as TestApi.
+     * This will be tracked and verified through cts.
+     */
+    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+    @TestApi
+    public static final class InstanceResourceInfo {
+        /**
+         * Identifier for the Resource type.
+         */
+        String mName;
+        /**
+         * Required resource count of this type.
+         */
+        long mStaticCount;
+        /**
+         * Per frame resource requirement of this resource type.
+         */
+        long mPerFrameCount;
+
+        @NonNull
+        public String getName() {
+            return mName;
+        }
+
+        public long getStaticCount() {
+            return mStaticCount;
+        }
+
+        public long getPerFrameCount() {
+            return mPerFrameCount;
+        }
+    };
+
+    /**
+     * @hide
+     * Get a list of required codec resources for this configuration.
+     *
+     * To be able to enforce and test the implementation of codec availability hal APIs,
+     * it is exposed only as TestApi.
+     * This will be tracked and verified through cts.
+     *
+     * This returns a {@link java.util.List} list of codec resources.
+     * For every {@link GlobalResourceInfo} in the list, it encapsulates the
+     * information about each resources required for the current configuration.
+     *
+     * NOTE: This may only be called after {@link #configure}.
+     *
+     * @return A list of required device codec resources; an empty list if no
+     *         device codec resources are required.
+     * @throws IllegalStateException if the codec wasn't configured yet.
+     * @throws UnsupportedOperationException if not implemented.
+     */
+    @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+    @TestApi
+    public @NonNull List<InstanceResourceInfo> getRequiredResources() {
+        return native_getRequiredResources();
+    }
+
+    @NonNull
+    private native List<InstanceResourceInfo> native_getRequiredResources();
+
+    /**
      *  Dynamically sets the output surface of a codec.
      *  <p>
      *  This can only be used if the codec was configured with an output surface.  The
@@ -5740,6 +5885,25 @@
                 @NonNull MediaCodec codec, @NonNull PersistableBundle metrics) {
             // default implementation ignores this callback.
         }
+
+        /**
+         * @hide
+         * Called when there is a change in the required resources for the codec.
+         * <p>
+         * Upon receiving this notification, the updated resource requirement
+         * can be queried through {@link #getRequiredResources}.
+         *
+         * @param codec The MediaCodec object.
+         */
+        @FlaggedApi(FLAG_CODEC_AVAILABILITY)
+        @TestApi
+        public void onRequiredResourcesChanged(@NonNull MediaCodec codec) {
+            /*
+             * A default implementation for backward compatibility.
+             * Since this is a TestApi, we are not enforcing the callback to be
+             * overridden.
+             */
+        }
     }
 
     private void postEventFromNative(
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index a0f8ae5..158bc7f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -18,7 +18,9 @@
 
 import static android.Manifest.permission.BIND_IMS_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -84,6 +86,7 @@
 import java.net.InetSocketAddress;
 import java.net.URL;
 import java.nio.ByteOrder;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.HashMap;
@@ -1542,6 +1545,8 @@
      * Note: The query is only valid if the MediaPlayer is currently playing.
      * If the player is not playing, the returned device can be null or correspond to previously
      * selected device when the player was last active.
+     * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and
+     * speaker on a phone), so prefer using {@link #getRoutedDevices}.
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
@@ -1552,6 +1557,23 @@
         return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
     }
 
+    /**
+     * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+     * MediaPlayer.
+     * Note: The query is only valid if the MediaPlayer is currently playing.
+     * If the player is not playing, the returned devices can be empty or correspond to previously
+     * selected devices when the player was last active.
+     */
+    @Override
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return audioDeviceInfos;
+    }
 
     /**
      * Sends device list change notification to all listeners.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 2d17bf5..f75bcf3 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS;
+
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -1695,6 +1698,24 @@
         return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
     }
 
+    /**
+     * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this
+     * MediaRecorder.
+     * Note: The query is only valid if the MediaRecorder is currently recording.
+     * If the recorder is not recording, the returned devices can be empty or correspond to
+     * previously selected devices when the recorder was last active.
+     */
+    @Override
+    @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
+    public @NonNull List<AudioDeviceInfo> getRoutedDevices() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        AudioDeviceInfo audioDeviceInfo = getRoutedDevice();
+        if (audioDeviceInfo != null) {
+            audioDeviceInfos.add(audioDeviceInfo);
+        }
+        return audioDeviceInfos;
+    }
+
     /*
      * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
      */
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 7895eb2..d8a8c8b 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -1,13 +1,7 @@
 package: "com.android.media.flags"
 container: "system"
 
-flag {
-    name: "enable_rlp_callbacks_in_media_router2"
-    is_exported: true
-    namespace: "media_solutions"
-    description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
-    bug: "281067101"
-}
+# Flags are ordered alphabetically by name.
 
 flag {
     name: "adjust_volume_for_foreground_app_playing_audio_without_media_session"
@@ -17,6 +11,13 @@
 }
 
 flag {
+    name: "enable_audio_input_device_routing_and_volume_control"
+    namespace: "media_better_together"
+    description: "Allows audio input devices routing and volume control via system settings."
+    bug: "355684672"
+}
+
+flag {
     name: "enable_audio_policies_device_and_bluetooth_controller"
     is_exported: true
     namespace: "media_solutions"
@@ -25,17 +26,54 @@
 }
 
 flag {
-    name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling"
-    namespace: "media_solutions"
-    description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
-    bug: "293743975"
+     name: "enable_built_in_speaker_route_suitability_statuses"
+     is_exported: true
+     namespace: "media_solutions"
+     description: "Make MediaRoute2Info provide information about routes suitability for transfer."
+     bug: "279555229"
 }
 
 flag {
-    name: "enable_waiting_state_for_system_session_creation_request"
+    name: "enable_cross_user_routing_in_media_router2"
+    is_exported: true
     namespace: "media_solutions"
-    description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
-    bug: "307723189"
+    description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
+    bug: "288580225"
+}
+
+flag {
+    name: "enable_full_scan_with_media_content_control"
+    namespace: "media_better_together"
+    description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground."
+    bug: "352401364"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "enable_get_transferable_routes"
+    is_exported: true
+    namespace: "media_solutions"
+    description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
+    bug: "323154573"
+}
+
+flag {
+    name: "enable_mirroring_in_media_router_2"
+    namespace: "media_better_together"
+    description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes."
+    bug: "362507305"
+}
+
+flag {
+    name: "enable_mr2_service_non_main_bg_thread"
+    namespace: "media_solutions"
+    description: "Enables the use of a background thread in the media routing framework, instead of using the main thread."
+    bug: "310145678"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -55,44 +93,6 @@
 }
 
 flag {
-    name: "enable_privileged_routing_for_media_routing_control"
-    is_exported: true
-    namespace: "media_solutions"
-    description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
-    bug: "305919655"
-}
-
-flag {
-    name: "enable_cross_user_routing_in_media_router2"
-    is_exported: true
-    namespace: "media_solutions"
-    description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users."
-    bug: "288580225"
-}
-
-flag {
-    name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name"
-    namespace: "media_solutions"
-    description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos."
-    bug: "314324170"
-}
-
-flag {
-    name: "update_client_profile_priority"
-    namespace: "media_solutions"
-    description : "Feature flag to add updateResourcePriority api to MediaCas"
-    bug: "300565729"
-}
-
-flag {
-     name: "enable_built_in_speaker_route_suitability_statuses"
-     is_exported: true
-     namespace: "media_solutions"
-     description: "Make MediaRoute2Info provide information about routes suitability for transfer."
-     bug: "279555229"
-}
-
-flag {
     name: "enable_notifying_activity_manager_with_media_session_status_change"
     is_exported: true
     namespace: "media_solutions"
@@ -101,11 +101,10 @@
 }
 
 flag {
-    name: "enable_get_transferable_routes"
-    is_exported: true
+    name: "enable_null_session_in_media_browser_service"
     namespace: "media_solutions"
-    description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API."
-    bug: "323154573"
+    description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers."
+    bug: "185136506"
 }
 
 flag {
@@ -116,31 +115,6 @@
 }
 
 flag {
-    name: "enable_mr2_service_non_main_bg_thread"
-    namespace: "media_solutions"
-    description: "Enables the use of a background thread in the media routing framework, instead of using the main thread."
-    bug: "310145678"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    name: "enable_screen_off_scanning"
-    is_exported: true
-    namespace: "media_solutions"
-    description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
-    bug: "281072508"
-}
-
-flag {
-    name: "enable_null_session_in_media_browser_service"
-    namespace: "media_solutions"
-    description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers."
-    bug: "185136506"
-}
-
-flag {
     name: "enable_prevention_of_manager_scans_when_no_apps_scan"
     namespace: "media_solutions"
     description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning."
@@ -151,25 +125,46 @@
 }
 
 flag {
-    name: "enable_full_scan_with_media_content_control"
-    namespace: "media_better_together"
-    description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground."
-    bug: "352401364"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
+    name: "enable_privileged_routing_for_media_routing_control"
+    is_exported: true
+    namespace: "media_solutions"
+    description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders."
+    bug: "305919655"
 }
 
 flag {
-    name: "enable_audio_input_device_routing_and_volume_control"
-    namespace: "media_better_together"
-    description: "Allows audio input devices routing and volume control via system settings."
-    bug: "355684672"
+    name: "enable_rlp_callbacks_in_media_router2"
+    is_exported: true
+    namespace: "media_solutions"
+    description: "Make RouteListingPreference getter and callbacks public in MediaRouter2."
+    bug: "281067101"
 }
 
 flag {
-    name: "enable_mirroring_in_media_router_2"
-    namespace: "media_better_together"
-    description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes."
-    bug: "362507305"
+    name: "enable_screen_off_scanning"
+    is_exported: true
+    namespace: "media_solutions"
+    description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off."
+    bug: "281072508"
+}
+
+flag {
+    name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name"
+    namespace: "media_solutions"
+    description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos."
+    bug: "314324170"
+}
+
+flag {
+    name: "enable_waiting_state_for_system_session_creation_request"
+    namespace: "media_solutions"
+    description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
+    bug: "307723189"
+}
+
+flag {
+    name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling"
+    namespace: "media_solutions"
+    description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
+    bug: "293743975"
 }
diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig
index 17d1ff6..1bb9a8e 100644
--- a/media/java/android/media/flags/projection.aconfig
+++ b/media/java/android/media/flags/projection.aconfig
@@ -18,3 +18,10 @@
     bug: "362720120"
     is_exported: true
 }
+
+flag {
+     namespace: "media_projection"
+     name: "stop_media_projection_on_call_end"
+     description: "Stops MediaProjection sessions when a call ends"
+     bug: "368336349"
+}
\ No newline at end of file
diff --git a/media/java/android/media/quality/AmbientBacklightEvent.java b/media/java/android/media/quality/AmbientBacklightEvent.java
index 3bc6b86..273f21e 100644
--- a/media/java/android/media/quality/AmbientBacklightEvent.java
+++ b/media/java/android/media/quality/AmbientBacklightEvent.java
@@ -16,9 +16,11 @@
 
 package android.media.quality;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.media.tv.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,8 +29,10 @@
 import java.util.Objects;
 
 /**
+ * Ambient backlight event
  * @hide
  */
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 public final class AmbientBacklightEvent implements Parcelable {
 
     /** @hide */
@@ -36,7 +40,7 @@
     @IntDef({AMBIENT_BACKLIGHT_EVENT_ENABLED, AMBIENT_BACKLIGHT_EVENT_DISABLED,
             AMBIENT_BACKLIGHT_EVENT_METADATA,
             AMBIENT_BACKLIGHT_EVENT_INTERRUPTED})
-    public @interface AmbientBacklightEventTypes {}
+    public @interface Type {}
 
     /**
      * Event type for ambient backlight events. The ambient backlight is enabled.
@@ -64,7 +68,10 @@
     @Nullable
     private final AmbientBacklightMetadata mMetadata;
 
-    public AmbientBacklightEvent(int eventType,
+    /**
+     * Constructs AmbientBacklightEvent.
+     */
+    public AmbientBacklightEvent(@Type int eventType,
             @Nullable AmbientBacklightMetadata metadata) {
         mEventType = eventType;
         mMetadata = metadata;
@@ -75,10 +82,20 @@
         mMetadata = in.readParcelable(AmbientBacklightMetadata.class.getClassLoader());
     }
 
+    /**
+     * Gets event type.
+     */
+    @Type
     public int getEventType() {
         return mEventType;
     }
 
+    /**
+     * Gets ambient backlight metadata.
+     *
+     * @return the metadata of the event. It's non-null only for
+     * {@link #AMBIENT_BACKLIGHT_EVENT_METADATA}.
+     */
     @Nullable
     public AmbientBacklightMetadata getMetadata() {
         return mMetadata;
@@ -95,7 +112,8 @@
         return 0;
     }
 
-    public static final @NonNull Parcelable.Creator<AmbientBacklightEvent> CREATOR =
+    @NonNull
+    public static final Parcelable.Creator<AmbientBacklightEvent> CREATOR =
             new Parcelable.Creator<AmbientBacklightEvent>() {
                 public AmbientBacklightEvent createFromParcel(Parcel in) {
                     return new AmbientBacklightEvent(in);
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java
index fc77934..5cea10d 100644
--- a/media/java/android/media/quality/AmbientBacklightMetadata.java
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.java
@@ -16,6 +16,10 @@
 
 package android.media.quality;
 
+import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
+import android.graphics.PixelFormat;
+import android.media.tv.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,9 +28,14 @@
 import java.util.Arrays;
 
 /**
+ * Metadata of ambient backlight.
+ *
+ * <p>A metadata instance is sent from ambient backlight hardware in a {@link AmbientBacklightEvent}
+ * with {@link AmbientBacklightEvent#AMBIENT_BACKLIGHT_EVENT_METADATA}.
  * @hide
  */
-public class AmbientBacklightMetadata implements Parcelable {
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
+public final class AmbientBacklightMetadata implements Parcelable {
     @NonNull
     private final String mPackageName;
     private final int mCompressAlgorithm;
@@ -37,8 +46,16 @@
     @NonNull
     private final int[] mZonesColors;
 
-    public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm,
-            int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber,
+    /**
+     * Constructs AmbientBacklightMetadata.
+     */
+    public AmbientBacklightMetadata(
+            @NonNull String packageName,
+            @AmbientBacklightSettings.CompressAlgorithm int compressAlgorithm,
+            @AmbientBacklightSettings.Source int source,
+            @PixelFormat.Format int colorFormat,
+            int horizontalZonesNumber,
+            int verticalZonesNumber,
             @NonNull int[] zonesColors) {
         mPackageName = packageName;
         mCompressAlgorithm = compressAlgorithm;
@@ -59,33 +76,65 @@
         mZonesColors = in.createIntArray();
     }
 
+    /**
+     * Gets package name of the metadata.
+     * @hide
+     */
     @NonNull
     public String getPackageName() {
         return mPackageName;
     }
 
+    /**
+     * Gets compress algorithm.
+     */
+    @AmbientBacklightSettings.CompressAlgorithm
     public int getCompressAlgorithm() {
         return mCompressAlgorithm;
     }
 
+    /**
+     * Gets source of ambient backlight detection.
+     */
+    @AmbientBacklightSettings.Source
     public int getSource() {
         return mSource;
     }
 
+    /**
+     * Gets color format.
+     */
+    @PixelFormat.Format
     public int getColorFormat() {
         return mColorFormat;
     }
 
+    /**
+     * Gets the number of horizontal color zones.
+     *
+     * <p>A color zone is a group of lights that always display the same color.
+     */
+    @IntRange(from = 0)
     public int getHorizontalZonesNumber() {
         return mHorizontalZonesNumber;
     }
 
+    /**
+     * Gets the number of vertical color zones.
+     *
+     * <p>A color zone is a group of lights that always display the same color.
+     */
+    @IntRange(from = 0)
     public int getVerticalZonesNumber() {
         return mVerticalZonesNumber;
     }
 
+    /**
+     * Gets color data of vertical color zones.
+     * @hide
+     */
     @NonNull
-    public int[] getZonesColors() {
+    public int[] getVerticalZonesColors() {
         return mZonesColors;
     }
 
diff --git a/media/java/android/media/quality/AmbientBacklightSettings.java b/media/java/android/media/quality/AmbientBacklightSettings.java
index bb782bf..d904cf7 100644
--- a/media/java/android/media/quality/AmbientBacklightSettings.java
+++ b/media/java/android/media/quality/AmbientBacklightSettings.java
@@ -16,7 +16,11 @@
 
 package android.media.quality;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.graphics.PixelFormat;
+import android.media.tv.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -26,10 +30,11 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Settings for ambient backlight.
+ * Settings to configure ambient backlight hardware.
  * @hide
  */
-public class AmbientBacklightSettings implements Parcelable {
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
+public final class AmbientBacklightSettings implements Parcelable {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SOURCE_NONE, SOURCE_AUDIO, SOURCE_VIDEO, SOURCE_AUDIO_VIDEO})
@@ -62,6 +67,7 @@
 
     /**
      * The color format is RGB888.
+     * @hide
      */
     public static final int COLOR_FORMAT_RGB888 = 1;
 
@@ -76,7 +82,7 @@
     public static final int ALGORITHM_NONE = 0;
 
     /**
-     * The compress algorithm is RLE.
+     * The compress algorithm is run length encoding (RLE).
      */
     public static final int ALGORITHM_RLE = 1;
 
@@ -115,8 +121,16 @@
      */
     private final int mThreshold;
 
-    public AmbientBacklightSettings(int source, int maxFps, int colorFormat,
-            int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted,
+    /**
+     * Constructs AmbientBacklightSettings.
+     */
+    public AmbientBacklightSettings(
+            @Source int source,
+            int maxFps,
+            @PixelFormat.Format int colorFormat,
+            int horizontalZonesNumber,
+            int verticalZonesNumber,
+            boolean isLetterboxOmitted,
             int threshold) {
         mSource = source;
         mMaxFps = maxFps;
@@ -137,32 +151,69 @@
         mThreshold = in.readInt();
     }
 
+    /**
+     * Gets source of ambient backlight detection.
+     */
     @Source
     public int getSource() {
         return mSource;
     }
 
+    /**
+     * Gets max frames per second.
+     */
+    @IntRange(from = 1)
     public int getMaxFps() {
         return mMaxFps;
     }
 
-    @ColorFormat
+    /**
+     * Gets color format.
+     */
+    @PixelFormat.Format
     public int getColorFormat() {
         return mColorFormat;
     }
 
+    /**
+     * Gets the number of horizontal color zones.
+     *
+     * <p>A color zone is a group of lights that always display the same color.
+     */
+    @IntRange(from = 0)
     public int getHorizontalZonesNumber() {
         return mHorizontalZonesNumber;
     }
 
+    /**
+     * Gets the number of vertical color zones.
+     *
+     * <p>A color zone is a group of lights that always display the same color.
+     */
+    @IntRange(from = 0)
     public int getVerticalZonesNumber() {
         return mVerticalZonesNumber;
     }
 
+    /**
+     * Returns {@code true} if the black portion of the screen in letter box mode is omitted;
+     * {@code false} otherwise.
+     *
+     * <p>Letter-box is a technique to keep the original aspect ratio when displayed on a screen
+     * with different aspect ratio. Black bars are added to the top and bottom.
+     * @hide
+     */
     public boolean isLetterboxOmitted() {
         return mIsLetterboxOmitted;
     }
 
+    /**
+     * Gets the detection threshold of the ambient light.
+     *
+     * <p>If the color of a color zone is changed by the difference is smaller than the threshold,
+     * the change is ignored.
+     * @hide
+     */
     public int getThreshold() {
         return mThreshold;
     }
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index 250d59b..aaedf21 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -42,10 +42,12 @@
     SoundProfile createSoundProfile(in SoundProfile pp);
     void updateSoundProfile(in String id, in SoundProfile pp);
     void removeSoundProfile(in String id);
-    SoundProfile getSoundProfileById(in String id);
+    SoundProfile getSoundProfile(in int type, in String name);
     List<SoundProfile> getSoundProfilesByPackage(in String packageName);
     List<SoundProfile> getAvailableSoundProfiles();
     List<String> getSoundProfilePackageNames();
+    List<String> getSoundProfileAllowList();
+    void setSoundProfileAllowList(in List<String> packages);
 
     void registerPictureProfileCallback(in IPictureProfileCallback cb);
     void registerSoundProfileCallback(in ISoundProfileCallback cb);
diff --git a/media/java/android/media/quality/ISoundProfileCallback.aidl b/media/java/android/media/quality/ISoundProfileCallback.aidl
index 72d1524..9043757 100644
--- a/media/java/android/media/quality/ISoundProfileCallback.aidl
+++ b/media/java/android/media/quality/ISoundProfileCallback.aidl
@@ -17,6 +17,7 @@
 
 package android.media.quality;
 
+import android.media.quality.ParamCapability;
 import android.media.quality.SoundProfile;
 
 /**
@@ -24,7 +25,9 @@
  * @hide
  */
 oneway interface ISoundProfileCallback {
-    void onSoundProfileAdded(in long id, in SoundProfile p);
-    void onSoundProfileUpdated(in long id, in SoundProfile p);
-    void onSoundProfileRemoved(in long id, in SoundProfile p);
+    void onSoundProfileAdded(in String id, in SoundProfile p);
+    void onSoundProfileUpdated(in String id, in SoundProfile p);
+    void onSoundProfileRemoved(in String id, in SoundProfile p);
+    void onParamCapabilitiesChanged(in String id, in List<ParamCapability> caps);
+    void onError(in int err);
 }
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 26d83ac..dcf4971 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -111,7 +111,7 @@
         };
         ISoundProfileCallback spCallback = new ISoundProfileCallback.Stub() {
             @Override
-            public void onSoundProfileAdded(long profileId, SoundProfile profile) {
+            public void onSoundProfileAdded(String profileId, SoundProfile profile) {
                 synchronized (mLock) {
                     for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
                         // TODO: filter callback record
@@ -120,7 +120,7 @@
                 }
             }
             @Override
-            public void onSoundProfileUpdated(long profileId, SoundProfile profile) {
+            public void onSoundProfileUpdated(String profileId, SoundProfile profile) {
                 synchronized (mLock) {
                     for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
                         // TODO: filter callback record
@@ -129,7 +129,7 @@
                 }
             }
             @Override
-            public void onSoundProfileRemoved(long profileId, SoundProfile profile) {
+            public void onSoundProfileRemoved(String profileId, SoundProfile profile) {
                 synchronized (mLock) {
                     for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
                         // TODO: filter callback record
@@ -137,6 +137,24 @@
                     }
                 }
             }
+            @Override
+            public void onParamCapabilitiesChanged(String profileId, List<ParamCapability> caps) {
+                synchronized (mLock) {
+                    for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
+                        // TODO: filter callback record
+                        record.postParamCapabilitiesChanged(profileId, caps);
+                    }
+                }
+            }
+            @Override
+            public void onError(int err) {
+                synchronized (mLock) {
+                    for (SoundProfileCallbackRecord record : mSpCallbackRecords) {
+                        // TODO: filter callback record
+                        record.postError(err);
+                    }
+                }
+            }
         };
         IAmbientBacklightCallback abCallback = new IAmbientBacklightCallback.Stub() {
             @Override
@@ -331,14 +349,17 @@
 
 
     /**
-     * Gets sound profile by given profile ID.
-     * @return the corresponding sound profile if available; {@code null} if the ID doesn't
-     *         exist or the profile is not accessible to the caller.
+     * Gets sound profile by given profile type and name.
+     *
+     * @return the corresponding sound profile if available; {@code null} if the name doesn't
+     *         exist.
      * @hide
      */
-    public SoundProfile getSoundProfileById(String profileId) {
+    @Nullable
+    public SoundProfile getSoundProfile(
+            @SoundProfile.ProfileType int type, @NonNull String name) {
         try {
-            return mService.getSoundProfileById(profileId);
+            return mService.getSoundProfile(type, name);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -349,8 +370,9 @@
      * @SystemApi gets profiles that available to the given package
      * @hide
      */
+    @NonNull
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
-    public List<SoundProfile> getSoundProfilesByPackage(String packageName) {
+    public List<SoundProfile> getSoundProfilesByPackage(@NonNull String packageName) {
         try {
             return mService.getSoundProfilesByPackage(packageName);
         } catch (RemoteException e) {
@@ -362,6 +384,7 @@
      * Gets profiles that available to the caller package
      * @hide
      */
+    @NonNull
     public List<SoundProfile> getAvailableSoundProfiles() {
         try {
             return mService.getAvailableSoundProfiles();
@@ -371,9 +394,12 @@
     }
 
     /**
-     * @SystemApi all stored sound profiles of all packages
+     * @SystemApi Gets all package names whose sound profiles are available.
+     *
+     * @see #getSoundProfilesByPackage(String)
      * @hide
      */
+    @NonNull
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
     public List<String> getSoundProfilePackageNames() {
         try {
@@ -387,12 +413,13 @@
     /**
      * Creates a sound profile and store it in the system.
      *
-     * @return the stored profile with an assigned profile ID.
+     * <p>If the profile is created successfully,
+     * {@link SoundProfileCallback#onSoundProfileAdded(long, SoundProfile)} is invoked.
      * @hide
      */
-    public SoundProfile createSoundProfile(SoundProfile sp) {
+    public void createSoundProfile(@NonNull SoundProfile sp) {
         try {
-            return mService.createSoundProfile(sp);
+            mService.createSoundProfile(sp);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -403,7 +430,7 @@
      * Updates an existing sound profile and store it in the system.
      * @hide
      */
-    public void updateSoundProfile(String profileId, SoundProfile sp) {
+    public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) {
         try {
             mService.updateSoundProfile(profileId, sp);
         } catch (RemoteException e) {
@@ -416,7 +443,7 @@
      * Removes a sound profile from the system.
      * @hide
      */
-    public void removeSoundProfile(String profileId) {
+    public void removeSoundProfile(@NonNull String profileId) {
         try {
             mService.removeSoundProfile(profileId);
         } catch (RemoteException e) {
@@ -468,6 +495,36 @@
     }
 
     /**
+     * Gets the allowlist of packages that can create and removed sound profiles
+     *
+     * @see #createSoundProfile(SoundProfile)
+     * @see #removeSoundProfile(String)
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+    @NonNull
+    public List<String> getSoundProfileAllowList() {
+        try {
+            return mService.getSoundProfileAllowList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the allowlist of packages that can create and removed sound profiles
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+    public void setSoundProfileAllowList(@NonNull List<String> packageNames) {
+        try {
+            mService.setSoundProfileAllowList(packageNames);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns {@code true} if media quality HAL is implemented; {@code false} otherwise.
      * @hide
      */
@@ -702,7 +759,7 @@
             return mCallback;
         }
 
-        public void postSoundProfileAdded(final long id, SoundProfile profile) {
+        public void postSoundProfileAdded(final String id, SoundProfile profile) {
 
             mExecutor.execute(new Runnable() {
                 @Override
@@ -712,7 +769,7 @@
             });
         }
 
-        public void postSoundProfileUpdated(final long id, SoundProfile profile) {
+        public void postSoundProfileUpdated(final String id, SoundProfile profile) {
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
@@ -721,7 +778,7 @@
             });
         }
 
-        public void postSoundProfileRemoved(final long id, SoundProfile profile) {
+        public void postSoundProfileRemoved(final String id, SoundProfile profile) {
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
@@ -729,6 +786,24 @@
                 }
             });
         }
+
+        public void postParamCapabilitiesChanged(final String id, List<ParamCapability> caps) {
+            mExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onParamCapabilitiesChanged(id, caps);
+                }
+            });
+        }
+
+        public void postError(int error) {
+            mExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onError(error);
+                }
+            });
+        }
     }
 
     private static final class AmbientBacklightCallbackRecord {
@@ -805,12 +880,13 @@
          * This is invoked when parameter capabilities has been changed due to status changes of the
          * content.
          *
-         * @param profileId the ID of the profile used by the media content.
+         * @param profileId the ID of the profile used by the media content. {@code null} if there
+         *                  is no associated profile
          * @param updatedCaps the updated capabilities.
          * @hide
          */
         public void onParamCapabilitiesChanged(
-                @NonNull String profileId, @NonNull List<ParamCapability> updatedCaps) {
+                @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) {
         }
     }
 
@@ -820,24 +896,58 @@
      */
     public abstract static class SoundProfileCallback {
         /**
+         * This is invoked when a sound profile has been added.
+         *
+         * @param profileId the ID of the profile.
+         * @param profile the newly added profile.
          * @hide
          */
-        public void onSoundProfileAdded(long id, SoundProfile profile) {
+        public void onSoundProfileAdded(
+                @NonNull String profileId, @NonNull SoundProfile profile) {
         }
+
         /**
+         * This is invoked when a sound profile has been updated.
+         *
+         * @param profileId the ID of the profile.
+         * @param profile the profile with updated info.
          * @hide
          */
-        public void onSoundProfileUpdated(long id, SoundProfile profile) {
+        public void onSoundProfileUpdated(
+                @NonNull String profileId, @NonNull SoundProfile profile) {
         }
+
         /**
+         * This is invoked when a sound profile has been removed.
+         *
+         * @param profileId the ID of the profile.
+         * @param profile the removed profile.
          * @hide
          */
-        public void onSoundProfileRemoved(long id, SoundProfile profile) {
+        public void onSoundProfileRemoved(
+                @NonNull String profileId, @NonNull SoundProfile profile) {
         }
+
         /**
+         * This is invoked when an issue has occurred.
+         *
+         * @param errorCode the error code
          * @hide
          */
-        public void onError(int errorCode) {
+        public void onError(@SoundProfile.ErrorCode int errorCode) {
+        }
+
+        /**
+         * This is invoked when parameter capabilities has been changed due to status changes of the
+         * content.
+         *
+         * @param profileId the ID of the profile used by the media content. {@code null} if there
+         *                  is no associated profile
+         * @param updatedCaps the updated capabilities.
+         * @hide
+         */
+        public void onParamCapabilitiesChanged(
+                @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) {
         }
     }
 
@@ -848,9 +958,8 @@
     public abstract static class AmbientBacklightCallback {
         /**
          * Called when new ambient backlight event is emitted.
-         * @hide
          */
-        public void onAmbientBacklightEvent(AmbientBacklightEvent event) {
+        public void onAmbientBacklightEvent(@NonNull AmbientBacklightEvent event) {
         }
     }
 }
diff --git a/media/java/android/media/quality/SoundProfile.java b/media/java/android/media/quality/SoundProfile.java
index 20d117b..de93afe 100644
--- a/media/java/android/media/quality/SoundProfile.java
+++ b/media/java/android/media/quality/SoundProfile.java
@@ -17,54 +17,119 @@
 package android.media.quality;
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.media.tv.TvInputInfo;
 import android.media.tv.flags.Flags;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
+ * Profile for sound quality.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 public class SoundProfile implements Parcelable {
     @Nullable
-    private Long mId;
+    private String mId;
+    private final int mType;
     @NonNull
     private final String mName;
     @Nullable
     private final String mInputId;
-    @Nullable
+    @NonNull
     private final String mPackageName;
     @NonNull
-    private final Bundle mParams;
+    private final PersistableBundle mParams;
 
-    protected SoundProfile(Parcel in) {
-        if (in.readByte() == 0) {
-            mId = null;
-        } else {
-            mId = in.readLong();
-        }
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, prefix = "TYPE_", value = {
+            TYPE_SYSTEM,
+            TYPE_APPLICATION})
+    public @interface ProfileType {}
+
+    /**
+     * System profile type.
+     *
+     * <p>A profile of system type is managed by the system, and readable to the package returned by
+     * {@link #getPackageName()}.
+     */
+    public static final int TYPE_SYSTEM = 1;
+    /**
+     * Application profile type.
+     *
+     * <p>A profile of application type is managed by the package returned by
+     * {@link #getPackageName()}.
+     */
+    public static final int TYPE_APPLICATION = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, prefix = "ERROR_", value = {
+            ERROR_UNKNOWN,
+            ERROR_NO_PERMISSION,
+            ERROR_DUPLICATE,
+            ERROR_INVALID_ARGUMENT,
+            ERROR_NOT_ALLOWLISTED
+    })
+    public @interface ErrorCode {}
+
+    /**
+     * Error code for unknown errors.
+     */
+    public static final int ERROR_UNKNOWN = 0;
+
+    /**
+     * Error code for missing necessary permission to handle the profiles.
+     */
+    public static final int ERROR_NO_PERMISSION = 1;
+
+    /**
+     * Error code for creating a profile with existing profile type and name.
+     *
+     * @see #getProfileType()
+     * @see #getName()
+     */
+    public static final int ERROR_DUPLICATE = 2;
+
+    /**
+     * Error code for invalid argument.
+     */
+    public static final int ERROR_INVALID_ARGUMENT = 3;
+
+    /**
+     * Error code for the case when an operation requires an allowlist but the caller is not in the
+     * list.
+     *
+     * @see MediaQualityManager#getSoundProfileAllowList()
+     */
+    public static final int ERROR_NOT_ALLOWLISTED = 4;
+
+    protected SoundProfile(@NonNull Parcel in) {
+        mId = in.readString();
+        mType = in.readInt();
         mName = in.readString();
         mInputId = in.readString();
         mPackageName = in.readString();
-        mParams = in.readBundle();
+        mParams = in.readPersistableBundle();
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        if (mId == null) {
-            dest.writeByte((byte) 0);
-        } else {
-            dest.writeByte((byte) 1);
-            dest.writeLong(mId);
-        }
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mId);
+        dest.writeInt(mType);
         dest.writeString(mName);
         dest.writeString(mInputId);
         dest.writeString(mPackageName);
-        dest.writeBundle(mParams);
+        dest.writePersistableBundle(mParams);
     }
 
     @Override
@@ -72,6 +137,7 @@
         return 0;
     }
 
+    @NonNull
     public static final Creator<SoundProfile> CREATOR = new Creator<SoundProfile>() {
         @Override
         public SoundProfile createFromParcel(Parcel in) {
@@ -91,93 +157,164 @@
      * @hide
      */
     public SoundProfile(
-            @Nullable Long id,
+            @Nullable String id,
+            int type,
             @NonNull String name,
             @Nullable String inputId,
-            @Nullable String packageName,
-            @NonNull Bundle params) {
+            @NonNull String packageName,
+            @NonNull PersistableBundle params) {
         this.mId = id;
+        this.mType = type;
         this.mName = name;
-        com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name);
         this.mInputId = inputId;
         this.mPackageName = packageName;
         this.mParams = params;
     }
 
+    /**
+     * Gets profile ID.
+     *
+     * <p>A profile ID is a globally unique ID generated and assigned by the system. For profile
+     * objects retrieved from system (e.g {@link MediaQualityManager#getAvailableSoundProfiles()})
+     * this profile ID is non-null; For profiles built locally with {@link Builder}, it's
+     * {@code null}.
+     *
+     * @return the unique profile ID; {@code null} if the profile is built locally with
+     * {@link Builder}.
+     */
     @Nullable
-    public Long getProfileId() {
+    public String getProfileId() {
         return mId;
     }
 
+    /**
+     * Only used by system to assign the ID.
+     * @hide
+     */
+    public void setProfileId(String id) {
+        mId = id;
+    }
+
+    /**
+     * Gets profile type.
+     */
+    @ProfileType
+    public int getProfileType() {
+        return mType;
+    }
+
+    /**
+     * Gets the profile name.
+     */
     @NonNull
     public String getName() {
         return mName;
     }
 
+    /**
+     * Gets the input ID if the profile is for a TV input.
+     *
+     * @return the corresponding TV input ID; {@code null} if the profile is not associated with a
+     * TV input.
+     *
+     * @see TvInputInfo#getId()
+     */
     @Nullable
     public String getInputId() {
         return mInputId;
     }
 
+    /**
+     * Gets the package name of this profile.
+     *
+     * <p>The package name defines the user of a profile. Only this specific package and system app
+     * can access to this profile.
+     *
+     * @return the package name; {@code null} if the profile is built locally using
+     * {@link Builder} and the package is not set.
+     */
     @Nullable
     public String getPackageName() {
         return mPackageName;
     }
+
+    /**
+     * Gets the parameters of this profile.
+     *
+     * <p>The keys of commonly used parameters can be found in
+     * {@link MediaQualityContract.SoundQuality}.
+     */
     @NonNull
-    public Bundle getParameters() {
-        return new Bundle(mParams);
+    public PersistableBundle getParameters() {
+        return new PersistableBundle(mParams);
     }
 
     /**
      * A builder for {@link SoundProfile}
+     * @hide
      */
     public static class Builder {
         @Nullable
-        private Long mId;
+        private String mId;
+        private int mType = TYPE_APPLICATION;
         @NonNull
         private String mName;
         @Nullable
         private String mInputId;
-        @Nullable
+        @NonNull
         private String mPackageName;
         @NonNull
-        private Bundle mParams;
+        private PersistableBundle mParams;
 
         /**
          * Creates a new Builder.
-         *
-         * @hide
          */
         public Builder(@NonNull String name) {
             mName = name;
-            com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name);
         }
 
         /**
-         * Copy constructor.
-         *
-         * @hide
+         * Copy constructor of builder.
          */
         public Builder(@NonNull SoundProfile p) {
             mId = null; // ID needs to be reset
+            mType = p.getProfileType();
             mName = p.getName();
             mPackageName = p.getPackageName();
             mInputId = p.getInputId();
+            mParams = p.getParameters();
         }
 
         /**
-         * Sets profile ID.
-         * @hide using by MediaQualityService
+         * Only used by system to assign the ID.
+         * @hide
          */
         @NonNull
-        public Builder setProfileId(@Nullable Long id) {
+        public Builder setProfileId(@Nullable String id) {
             mId = id;
             return this;
         }
 
         /**
-         * Sets input ID.
+         * Sets profile type.
+         *
+         * @hide
          */
+        @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+        @NonNull
+        public Builder setProfileType(@ProfileType int value) {
+            mType = value;
+            return this;
+        }
+
+        /**
+         * Sets input ID.
+         *
+         * @see SoundProfile#getInputId()
+         *
+         * @hide
+         */
+        @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
         @NonNull
         public Builder setInputId(@NonNull String value) {
             mInputId = value;
@@ -186,7 +323,12 @@
 
         /**
          * Sets package name of the profile.
+         *
+         * @see SoundProfile#getPackageName()
+         *
+         * @hide
          */
+        @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
         @NonNull
         public Builder setPackageName(@NonNull String value) {
             mPackageName = value;
@@ -195,12 +337,15 @@
 
         /**
          * Sets profile parameters.
+         *
+         * @see SoundProfile#getParameters()
          */
         @NonNull
-        public Builder setParameters(@NonNull Bundle params) {
-            mParams = new Bundle(params);
+        public Builder setParameters(@NonNull PersistableBundle params) {
+            mParams = new PersistableBundle(params);
             return this;
         }
+
         /**
          * Builds the instance.
          */
@@ -209,6 +354,7 @@
 
             SoundProfile o = new SoundProfile(
                     mId,
+                    mType,
                     mName,
                     mInputId,
                     mPackageName,
diff --git a/media/java/android/media/tv/ad/TvAdView.java b/media/java/android/media/tv/ad/TvAdView.java
index dd2a534..ff0279f 100644
--- a/media/java/android/media/tv/ad/TvAdView.java
+++ b/media/java/android/media/tv/ad/TvAdView.java
@@ -240,6 +240,38 @@
         }
     }
 
+    /**
+     * Controls whether the TvAdView's surface is placed on top of other regular surface views in
+     * the window (but still behind the window itself).
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
+     *
+     * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
+     *            otherwise.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
+    public void setZOrderMediaOverlay(boolean isMediaOverlay) {
+        if (mSurfaceView != null) {
+            mSurfaceView.setZOrderOnTop(false);
+            mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
+        }
+    }
+
+    /**
+     * Controls whether the TvAdView's surface is placed on top of its window.
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
+     *
+     * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW)
+    public void setZOrderOnTop(boolean onTop) {
+        if (mSurfaceView != null) {
+            mSurfaceView.setZOrderMediaOverlay(false);
+            mSurfaceView.setZOrderOnTop(onTop);
+        }
+    }
+
     private void resetSurfaceView() {
         if (mSurfaceView != null) {
             mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
diff --git a/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl
new file mode 100644
index 0000000..2a2e71a
--- /dev/null
+++ b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.oad;
+
+/**
+ * @hide
+ */
+interface IOadUpdateInterface {
+    // Enable or disable the OAD function.
+    void setOadStatus(boolean enable);
+    // Get status of OAD function.
+    boolean getOadStatus();
+    // Start OAD scan of all frequency in the program list.
+    void startScan();
+    // Stop OAD scan of all frequency in the program list.
+    void stopScan();
+    // Start OAD detect for the current channel.
+    void startDetect();
+    // Stop OAD detect for the current channel.
+    void stopDetect();
+    // Start OAD download after it has been detected or scanned.
+    void startDownload();
+    // Stop OAD download.
+    void stopDownload();
+    // Retrieves current OAD software version.
+    int getSoftwareVersion();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
similarity index 73%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
index e4ccc2c..bf1a385 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.rating;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IDownloadableRatingTableMonitor {
+    // Get RRT rating info on downloadable rating data
+    Bundle[] getTable();
+}
diff --git a/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl
new file mode 100644
index 0000000..06cac3d
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.rating;
+
+import android.media.tv.extension.rating.IPmtRatingListener;
+
+/**
+ * @hide
+ */
+interface IPmtRatingInterface {
+    // Get Pmt rating information.
+    String getPmtRating(String sessionToken);
+    // Register a listener for pmt rating updates.
+    void addPmtRatingListener(String clientToken, in IPmtRatingListener listener);
+    // Remove the previously added IPmtRatingListener.
+    void removePmtRatingListener(in IPmtRatingListener listener);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
similarity index 76%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
index e4ccc2c..d88ae94 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.rating;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/**
+ * @hide
+ */
+oneway interface IPmtRatingListener {
+    void onPmtRatingChanged(String sessionToken, String newTvContentRating);
+}
diff --git a/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl
new file mode 100644
index 0000000..a490491
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.rating;
+
+import android.media.tv.extension.rating.IProgramRatingInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IProgramRatingInfo {
+    // Register a listener to receive notifications when ProgramRatingInfo is updated.
+    void addProgramRatingInfoListener(String clientToken, in IProgramRatingInfoListener listener);
+    // Remove a listener for ProgramRatingInfo update notifications.
+    void removeProgramRatingInfoListener(in IProgramRatingInfoListener listener);
+    // Get ProgramRatingInfo that may only be obtained when viewing.
+    Bundle getProgramRatingInfo(String sessionToken);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
index e4ccc2c..6777cd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.rating;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IProgramRatingInfoListener {
+    void onProgramInfoChanged(String sessionToken,in Bundle changedProgramInfo);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to media/java/android/media/tv/extension/rating/IRatingInterface.aidl
index e4ccc2c..d68fe76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl
@@ -14,10 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.rating;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IRatingInterface {
+    // Get RRT rating information
+    Bundle getRRTRatingInfo();
+    // Set RRT rating information when user select
+    boolean setRRTRatingInfo(in Bundle param);
+    // Reset RRT5 to clear information
+    boolean setResetRrt5();
+}
diff --git a/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl
new file mode 100644
index 0000000..bad4067
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.rating;
+
+import android.media.tv.extension.rating.IVbiRatingListener;
+
+/**
+ * @hide
+ */
+interface IVbiRatingInterface {
+    // Get Vbi rating.
+    String getVbiRating(String sessionToken);
+    // Register a listener for Vbi rating updates.
+    void addVbiRatingListener(String clientToken, in IVbiRatingListener listener);
+    // Remove the previously added VbiRatingListener.
+    void removeVbiRatingListener(in IVbiRatingListener listener);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
similarity index 76%
rename from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
rename to media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
index e4ccc2c..36d523f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.rating;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/**
+ * @hide
+ */
+oneway interface IVbiRatingListener {
+    void onVbiRatingChanged(String sessionToken, String newTvContentRating);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
similarity index 67%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to media/java/android/media/tv/extension/time/IBroadcastTime.aidl
index e4ccc2c..123d00f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
@@ -14,10 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package android.media.tv.extension.time;
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IBroadcastTime {
+    long getUtcTime();
+    long getLocalTime();
+    Bundle getTimeZoneInfo();
+    long getUtcTimePerStream(String SessionToken);
+    long getLocalTimePerStream(String SessionToken);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig
index 4de6863..4b832ae 100644
--- a/media/java/android/media/tv/flags/media_tv.aconfig
+++ b/media/java/android/media/tv/flags/media_tv.aconfig
@@ -2,6 +2,22 @@
 container: "system"
 
 flag {
+    name: "enable_le_audio_broadcast_ui"
+    is_exported: true
+    namespace: "media_tv"
+    description: "Enable Broadcast UI for LE Audio on TV."
+    bug: "378732734"
+}
+
+flag {
+    name: "enable_le_audio_unicast_ui"
+    is_exported: true
+    namespace: "media_tv"
+    description: "Enable Unicast UI for LE Audio on TV."
+    bug: "378732734"
+}
+
+flag {
     name: "broadcast_visibility_types"
     is_exported: true
     namespace: "media_tv"
@@ -77,6 +93,22 @@
     name: "set_resource_holder_retain"
     is_exported: true
     namespace: "media_tv"
-    description : "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA."
+    description: "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA."
     bug: "372973197"
 }
+
+flag {
+    name: "mediacas_update_client_profile_priority"
+    is_exported: true
+    namespace: "media_tv"
+    description: "Feature flag to add updateResourcePriority api to MediaCas"
+    bug: "372971241"
+}
+
+flag {
+    name: "apply_picture_profiles"
+    is_exported: true
+    namespace: "media_tv"
+    description : "Feature flag to enable APIs for applying picture profiles"
+    bug: "337330263"
+}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 635572d..9e9699f 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -271,6 +271,38 @@
         }
     }
 
+    /**
+     * Controls whether the TvInteractiveAppView's surface is placed on top of other regular surface
+     * views in the window (but still behind the window itself).
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
+     *
+     * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
+     *            otherwise.
+     */
+    @FlaggedApi(Flags.FLAG_TIAF_V_APIS)
+    public void setZOrderMediaOverlay(boolean isMediaOverlay) {
+        if (mSurfaceView != null) {
+            mSurfaceView.setZOrderOnTop(false);
+            mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
+        }
+    }
+
+    /**
+     * Controls whether the TvInterActiveAppView's surface is placed on top of its window.
+     *
+     * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
+     *
+     * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
+     */
+    @FlaggedApi(Flags.FLAG_TIAF_V_APIS)
+    public void setZOrderOnTop(boolean onTop) {
+        if (mSurfaceView != null) {
+            mSurfaceView.setZOrderMediaOverlay(false);
+            mSurfaceView.setZOrderOnTop(onTop);
+        }
+    }
+
     private void resetSurfaceView() {
         if (mSurfaceView != null) {
             mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index c44e26f..f09dc72 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -104,6 +104,7 @@
         "libgrallocusage",
         "libmedia_midiiowrapper",
         "android.companion.virtualdevice.flags-aconfig-cc",
+        "android.media.codec-aconfig-cc",
         "android.media.playback.flags-aconfig-cc",
     ],
 
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 001653b..fc184fe 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -39,6 +39,8 @@
 #include <C2Buffer.h>
 #include <C2PlatformSupport.h>
 
+#include <android_media_codec.h>
+
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -189,6 +191,22 @@
     jmethodID setId;
 } gBufferInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID ctorId;
+    jfieldID resourceId;
+    jfieldID capacityId;
+    jfieldID availableId;
+} gGlobalResourceInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID ctorId;
+    jfieldID resourceId;
+    jfieldID staticCountId;
+    jfieldID perFrameCountId;
+} gInstanceResourceInfo;
+
 struct fields_t {
     jmethodID postEventFromNativeID;
     jmethodID lockAndGetContextID;
@@ -1129,6 +1147,37 @@
     return mCodec->unsubscribeFromVendorParameters(names);
 }
 
+static jobject getJavaResources(
+        JNIEnv *env,
+        const std::vector<MediaCodec::InstanceResourceInfo>& resources) {
+    jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+    for (const MediaCodec::InstanceResourceInfo& res : resources) {
+        ScopedLocalRef<jobject> object{env, env->NewObject(
+                gInstanceResourceInfo.clazz, gInstanceResourceInfo.ctorId)};
+        ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
+        env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
+        env->SetLongField(object.get(),
+                          gInstanceResourceInfo.staticCountId,
+                          (jlong)res.mStaticCount);
+        env->SetLongField(object.get(),
+                          gInstanceResourceInfo.perFrameCountId,
+                          (jlong)res.mPerFrameCount);
+        (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
+    }
+
+    return resourcesObj;
+}
+
+status_t JMediaCodec::getRequiredResources(JNIEnv *env, jobject *resourcesObj) {
+    std::vector<MediaCodec::InstanceResourceInfo> resources;
+    status_t status = mCodec->getRequiredResources(resources);
+    if (status != OK) {
+        return status;
+    }
+    *resourcesObj = getJavaResources(env, resources);
+    return OK;
+}
+
 static jthrowable createCodecException(
         JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
     ScopedLocalRef<jclass> clazz(
@@ -1475,6 +1524,10 @@
             obj = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
             break;
         }
+        case MediaCodec::CB_REQUIRED_RESOURCES_CHANGED:
+        {
+            break;
+        }
 
         default:
             TRESPASS();
@@ -3560,6 +3613,64 @@
     return;
 }
 
+static jobject getJavaResources(
+        JNIEnv *env,
+        const std::vector<MediaCodec::GlobalResourceInfo>& resources) {
+    jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+    for (const MediaCodec::GlobalResourceInfo& res : resources) {
+        ScopedLocalRef<jobject> object{env, env->NewObject(
+                gGlobalResourceInfo.clazz, gGlobalResourceInfo.ctorId)};
+        ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())};
+        env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get());
+        env->SetLongField(object.get(), gGlobalResourceInfo.capacityId, (jlong)res.mCapacity);
+        env->SetLongField(object.get(), gGlobalResourceInfo.availableId, (jlong)res.mAvailable);
+        (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get());
+    }
+
+    return resourcesObj;
+}
+
+static jobject android_media_MediaCodec_getGloballyAvailableResources(
+        JNIEnv *env, jobject thiz) {
+    (void)thiz;
+    std::vector<MediaCodec::GlobalResourceInfo> resources;
+    status_t status = MediaCodec::getGloballyAvailableResources(resources);
+    if (status != OK) {
+        if (status == ERROR_UNSUPPORTED) {
+            jniThrowException(env, "java/lang/UnsupportedOperationException",
+                              "Function Not Implemented");
+        } else {
+            throwExceptionAsNecessary(env, status, nullptr);
+        }
+        return nullptr;
+    }
+
+    return getJavaResources(env, resources);
+}
+
+static jobject android_media_MediaCodec_getRequiredResources(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+    if (codec == nullptr || codec->initCheck() != OK) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+        return nullptr;
+    }
+
+    jobject ret = nullptr;
+    status_t status = codec->getRequiredResources(env, &ret);
+    if (status != OK) {
+        if (status == ERROR_UNSUPPORTED) {
+            jniThrowException(env, "java/lang/UnsupportedOperationException",
+                              "Function Not Implemented");
+        } else {
+            throwExceptionAsNecessary(env, status, nullptr);
+        }
+        return nullptr;
+    }
+
+    return ret;
+}
+
 static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
     ScopedLocalRef<jclass> clazz(
             env, env->FindClass("android/media/MediaCodec"));
@@ -3905,6 +4016,36 @@
     gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
     gFields.bufferInfoPresentationTimeUs =
             env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
+
+    // Since these TestApis are defined under the flag, make sure they are
+    // accessed only when the flag is set.
+    if (android::media::codec::codec_availability()) {
+        clazz.reset(env->FindClass("android/media/MediaCodec$GlobalResourceInfo"));
+        CHECK(clazz.get() != NULL);
+        gGlobalResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+        gGlobalResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+        CHECK(gGlobalResourceInfo.ctorId != NULL);
+        gGlobalResourceInfo.resourceId =
+                env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+        CHECK(gGlobalResourceInfo.resourceId != NULL);
+        gGlobalResourceInfo.capacityId = env->GetFieldID(clazz.get(), "mCapacity", "J");
+        CHECK(gGlobalResourceInfo.capacityId != NULL);
+        gGlobalResourceInfo.availableId = env->GetFieldID(clazz.get(), "mAvailable", "J");
+        CHECK(gGlobalResourceInfo.availableId != NULL);
+
+        clazz.reset(env->FindClass("android/media/MediaCodec$InstanceResourceInfo"));
+        CHECK(clazz.get() != NULL);
+        gInstanceResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+        gInstanceResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+        CHECK(gInstanceResourceInfo.ctorId != NULL);
+        gInstanceResourceInfo.resourceId =
+                env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+        CHECK(gInstanceResourceInfo.resourceId != NULL);
+        gInstanceResourceInfo.staticCountId= env->GetFieldID(clazz.get(), "mStaticCount", "J");
+        CHECK(gInstanceResourceInfo.staticCountId != NULL);
+        gInstanceResourceInfo.perFrameCountId = env->GetFieldID(clazz.get(), "mPerFrameCount", "J");
+        CHECK(gInstanceResourceInfo.perFrameCountId != NULL);
+    }
 }
 
 static void android_media_MediaCodec_native_setup(
@@ -4261,6 +4402,12 @@
 
     { "native_finalize", "()V",
       (void *)android_media_MediaCodec_native_finalize },
+
+    { "native_getGloballyAvailableResources", "()Ljava/util/List;",
+      (void *)android_media_MediaCodec_getGloballyAvailableResources},
+
+    { "native_getRequiredResources", "()Ljava/util/List;",
+      (void *)android_media_MediaCodec_getRequiredResources},
 };
 
 static const JNINativeMethod gLinearBlockMethods[] = {
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c9b6b7f6..930dbbe 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -185,6 +185,8 @@
 
     status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);
 
+    status_t getRequiredResources(JNIEnv *env, jobject *resourcesObj);
+
     bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
 
     const sp<ICrypto> &getCrypto() { return mCrypto; }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index ac85ab7..88c1c43 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -257,6 +257,16 @@
         public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
             // TODO Auto-generated method stub
         }
+
+        /*
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged
+         */
+        @Override
+        public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+            // TODO Auto-generated method stub
+        }
+
     }
 
     @SmallTest
@@ -276,7 +286,7 @@
                         0 /*oomScoreOffset*/,
                         getContext().getApplicationInfo().targetSdkVersion,
                         ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution,
-                        DEVICE_POLICY_DEFAULT);
+                        DEVICE_POLICY_DEFAULT, false/*sharedMode*/);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -320,6 +330,13 @@
             Log.v(TAG, String.format("Camera " + cameraId + " torch strength level changed to "
                     + torchStrength ));
         }
+        @Override
+        public void onCameraOpenedInSharedMode(String cameraId, String clientPackageName,
+                int deviceId, boolean primaryClient) {
+            Log.v(TAG, "Camera " + cameraId +  " is opened in shared mode by "
+                    + "client package "  + clientPackageName + " as primary client="
+                    + primaryClient);
+        }
     }
 
     /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 35ad924..3758c51 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -175,6 +175,15 @@
         public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
             // TODO Auto-generated method stub
         }
+
+        /**
+         * (non-Javadoc)
+         * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged
+         */
+        @Override
+        public void onClientSharedAccessPriorityChanged(boolean primaryClient) {
+            // TODO Auto-generated method stub
+        }
     }
 
     class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataNative> {
@@ -250,7 +259,8 @@
 
         mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
                 /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion,
-                ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT);
+                ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT,
+                /*sharedMode*/false);
         assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index a046057..2d1fbf9 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -361,6 +361,8 @@
     APerformanceHint_setThreads; # introduced=UpsideDownCake
     APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
     APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream
+    APerformanceHint_notifyWorkloadIncrease; # introduced=36
+    APerformanceHint_notifyWorkloadReset; # introduced=36
     AWorkDuration_create; # introduced=VanillaIceCream
     AWorkDuration_release; # introduced=VanillaIceCream
     AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
@@ -379,6 +381,8 @@
     APerformanceHint_getThreadIds;
     APerformanceHint_createSessionInternal;
     APerformanceHint_setUseFMQForTesting;
+    APerformanceHint_getRateLimiterPropertiesForTesting;
+    APerformanceHint_setUseNewLoadHintBehaviorForTesting;
     extern "C++" {
         ASurfaceControl_registerSurfaceStatsListener*;
         ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 15f77ce..e2fa94d 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -33,12 +33,14 @@
 #include <android/performance_hint.h>
 #include <android/trace.h>
 #include <android_os.h>
+#include <cutils/trace.h>
 #include <fmq/AidlMessageQueue.h>
 #include <inttypes.h>
 #include <performance_hint_private.h>
 #include <utils/SystemClock.h>
 
 #include <chrono>
+#include <format>
 #include <future>
 #include <set>
 #include <utility>
@@ -63,6 +65,22 @@
 constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
 struct AWorkDuration : public hal::WorkDuration {};
 
+// A pair of values that determine the behavior of the
+// load hint rate limiter, to only allow "X hints every Y seconds"
+constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
+constexpr double kMaxLoadHintsPerInterval = 20;
+constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
+bool kForceNewHintBehavior = false;
+
+template <class T>
+constexpr int32_t enum_size() {
+    return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
+}
+
+bool useNewLoadHintBehavior() {
+    return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
+}
+
 // Shared lock for the whole PerformanceHintManager and sessions
 static std::mutex sHintMutex = std::mutex{};
 class FMQWrapper {
@@ -76,7 +94,8 @@
                                    hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
     bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
                                   int64_t targetDurationNanos) REQUIRES(sHintMutex);
-    bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
+    bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
+                   int64_t now) REQUIRES(sHintMutex);
     bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
             REQUIRES(sHintMutex);
     void setToken(ndk::SpAIBinder& token);
@@ -86,10 +105,11 @@
 private:
     template <HalChannelMessageContents::Tag T, bool urgent = false,
               class C = HalChannelMessageContents::_at<T>>
-    bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
-            REQUIRES(sHintMutex);
+    bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
+                      int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
     template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
-    void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
+    void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
+            REQUIRES(sHintMutex);
 
     bool isActiveLocked() REQUIRES(sHintMutex);
     bool updatePersistentTransaction() REQUIRES(sHintMutex);
@@ -120,6 +140,7 @@
                                            hal::SessionTag tag = hal::SessionTag::APP);
     int64_t getPreferredRateNanos() const;
     FMQWrapper& getFMQWrapper();
+    bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
 
 private:
     // Necessary to create an empty binder object
@@ -138,6 +159,8 @@
     ndk::SpAIBinder mToken;
     const int64_t mPreferredRateNanos;
     FMQWrapper mFMQWrapper;
+    double mHintBudget = kMaxLoadHintsPerInterval;
+    int64_t mLastBudgetReplenish = 0;
 };
 
 struct APerformanceHintSession {
@@ -151,7 +174,9 @@
 
     int updateTargetWorkDuration(int64_t targetDurationNanos);
     int reportActualWorkDuration(int64_t actualDurationNanos);
-    int sendHint(SessionHint hint);
+    int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
+    int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
+    int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
     int setThreads(const int32_t* threadIds, size_t size);
     int getThreadIds(int32_t* const threadIds, size_t* size);
     int setPreferPowerEfficiency(bool enabled);
@@ -173,6 +198,8 @@
     // Last target hit timestamp
     int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
     // Last hint reported from sendHint indexed by hint value
+    // This is only used by the old rate limiter impl and is replaced
+    // with the new rate limiter under a flag
     std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
     // Cached samples
     std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
@@ -255,6 +282,21 @@
     return new APerformanceHintManager(manager, preferredRateNanos);
 }
 
+bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
+    mHintBudget =
+            std::max(kMaxLoadHintsPerInterval,
+                     mHintBudget +
+                             static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
+    mLastBudgetReplenish = now;
+
+    // If this youngest timestamp isn't older than the timeout time, we can't send
+    if (hints.size() > mHintBudget) {
+        return false;
+    }
+    mHintBudget -= hints.size();
+    return true;
+}
+
 APerformanceHintSession* APerformanceHintManager::createSession(
         const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
         hal::SessionTag tag) {
@@ -292,9 +334,7 @@
 
 // ===================================== APerformanceHintSession implementation
 
-constexpr int kNumEnums =
-        ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
-
+constexpr int kNumEnums = enum_size<hal::SessionHint>();
 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                                                  std::shared_ptr<IHintSession> session,
                                                  int64_t preferredRateNanos,
@@ -361,31 +401,83 @@
     return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
 }
 
-int APerformanceHintSession::sendHint(SessionHint hint) {
+int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
+                                       const char*) {
     std::scoped_lock lock(sHintMutex);
-    if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
-        ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
+    if (hints.empty()) {
         return EINVAL;
     }
-    int64_t now = uptimeNanos();
-
-    // Limit sendHint to a pre-detemined rate for safety
-    if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
-        return 0;
-    }
-
-    if (!getFMQ().sendHint(mSessionConfig, hint)) {
-        ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
-
-        if (!ret.isOk()) {
-            ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
-            return EPIPE;
+    for (auto&& hint : hints) {
+        if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
+            ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
+            return EINVAL;
         }
     }
-    mLastHintSentTimestamp[hint] = now;
+
+    if (useNewLoadHintBehavior()) {
+        if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
+            return EBUSY;
+        }
+    }
+    // keep old rate limiter behavior for legacy flag
+    else {
+        for (auto&& hint : hints) {
+            if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
+                return EBUSY;
+            }
+        }
+    }
+
+    if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
+        for (auto&& hint : hints) {
+            ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
+
+            if (!ret.isOk()) {
+                ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
+                return EPIPE;
+            }
+        }
+    }
+
+    if (!useNewLoadHintBehavior()) {
+        for (auto&& hint : hints) {
+            mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
+        }
+    }
+
+    if (ATrace_isEnabled()) {
+        ATRACE_INSTANT("Sending load hint");
+    }
+
     return 0;
 }
 
+int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
+    std::vector<hal::SessionHint> hints(2);
+    hints.clear();
+    if (cpu) {
+        hints.push_back(hal::SessionHint::CPU_LOAD_UP);
+    }
+    if (gpu) {
+        hints.push_back(hal::SessionHint::GPU_LOAD_UP);
+    }
+    int64_t now = ::android::uptimeNanos();
+    return sendHints(hints, now, debugName);
+}
+
+int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
+    std::vector<hal::SessionHint> hints(2);
+    hints.clear();
+    if (cpu) {
+        hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
+    }
+    if (gpu) {
+        hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
+    }
+    int64_t now = ::android::uptimeNanos();
+    return sendHints(hints, now, debugName);
+}
+
 int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
     if (size == 0) {
         ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
@@ -565,24 +657,25 @@
 }
 
 template <HalChannelMessageContents::Tag T, class C>
-void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
-    new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
-            .sessionID = static_cast<int32_t>(config.id),
-            .timeStampNanos = ::android::uptimeNanos(),
-            .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
-    };
+void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
+    for (size_t i = 0; i < count; ++i) {
+        new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
+                .sessionID = static_cast<int32_t>(config.id),
+                .timeStampNanos = now,
+                .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
+        };
+    }
 }
 
 template <>
 void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
                                                                       hal::SessionConfig& config,
-                                                                      size_t count) {
+                                                                      size_t count, int64_t now) {
     for (size_t i = 0; i < count; ++i) {
         hal::WorkDuration& message = messages[i];
         new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
                 .sessionID = static_cast<int32_t>(config.id),
-                .timeStampNanos =
-                        (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
+                .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
                 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
                                                         hal::WorkDurationFixedV1>({
                         .durationNanos = message.cpuDurationNanos,
@@ -595,7 +688,8 @@
 }
 
 template <HalChannelMessageContents::Tag T, bool urgent, class C>
-bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
+bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
+                              int64_t now) {
     if (!isActiveLocked() || !config.has_value() || mCorrupted) {
         return false;
     }
@@ -609,7 +703,7 @@
             return false;
         }
     }
-    writeBuffer<T, C>(message, *config, count);
+    writeBuffer<T, C>(message, *config, count, now);
     mQueue->commitWrite(count);
     mEventFlag->wake(mWriteMask);
     // Re-create the persistent transaction after writing
@@ -641,10 +735,9 @@
     return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
 }
 
-bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
-    return sendMessages<HalChannelMessageContents::hint>(config,
-                                                         reinterpret_cast<hal::SessionHint*>(
-                                                                 &hint));
+bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
+                           std::vector<hal::SessionHint>& hints, int64_t now) {
+    return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
 }
 
 bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
@@ -758,7 +851,9 @@
 
 int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
     VALIDATE_PTR(session)
-    return session->sendHint(hint);
+    std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
+    int64_t now = ::android::uptimeNanos();
+    return session->sendHints(hints, now, "HWUI hint");
 }
 
 int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
@@ -791,6 +886,26 @@
     return session->reportActualWorkDuration(workDurationPtr);
 }
 
+int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
+                                            const char* debugName) {
+    VALIDATE_PTR(session)
+    VALIDATE_PTR(debugName)
+    if (!useNewLoadHintBehavior()) {
+        return ENOTSUP;
+    }
+    return session->notifyWorkloadIncrease(cpu, gpu, debugName);
+}
+
+int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
+                                         const char* debugName) {
+    VALIDATE_PTR(session)
+    VALIDATE_PTR(debugName)
+    if (!useNewLoadHintBehavior()) {
+        return ENOTSUP;
+    }
+    return session->notifyWorkloadReset(cpu, gpu, debugName);
+}
+
 AWorkDuration* AWorkDuration_create() {
     return new AWorkDuration();
 }
@@ -838,3 +953,13 @@
 void APerformanceHint_setUseFMQForTesting(bool enabled) {
     gForceFMQEnabled = enabled;
 }
+
+void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
+                                                         int64_t* loadHintInterval) {
+    *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
+    *loadHintInterval = kLoadHintInterval;
+}
+
+void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
+    kForceNewHintBehavior = newBehavior;
+}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 9de3a6f..f707a0e 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -66,6 +66,18 @@
                  std::optional<hal::ChannelConfig>* _aidl_return),
                 (override));
     MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
+    MOCK_METHOD(ScopedAStatus, getCpuHeadroom,
+                (const ::aidl::android::os::CpuHeadroomParamsInternal& in_params,
+                 std::vector<float>* _aidl_return),
+                (override));
+    MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
+                (override));
+    MOCK_METHOD(ScopedAStatus, getGpuHeadroom,
+                (const ::aidl::android::os::GpuHeadroomParamsInternal& in_params,
+                 float* _aidl_return),
+                (override));
+    MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
+                (override));
     MOCK_METHOD(SpAIBinder, asBinder, (), (override));
     MOCK_METHOD(bool, isRemote, (), (override));
 };
@@ -90,7 +102,10 @@
 public:
     void SetUp() override {
         mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>();
+        APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval,
+                                                            &mLoadHintInterval);
         APerformanceHint_setIHintManagerForTesting(&mMockIHintManager);
+        APerformanceHint_setUseNewLoadHintBehaviorForTesting(true);
     }
 
     void TearDown() override {
@@ -176,6 +191,9 @@
     int kMockQueueSize = 20;
     bool mUsingFMQ = false;
 
+    int32_t mMaxLoadHintsPerInterval;
+    int64_t mLoadHintInterval;
+
     template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
     void expectToReadFromFmq(C expected) {
         hal::ChannelMessage readData;
@@ -218,7 +236,6 @@
     EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1));
     result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
     EXPECT_EQ(0, result);
-
     result = APerformanceHint_updateTargetWorkDuration(session, -1L);
     EXPECT_EQ(EINVAL, result);
     result = APerformanceHint_reportActualWorkDuration(session, -1L);
@@ -228,18 +245,28 @@
     EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1));
     result = APerformanceHint_sendHint(session, hintId);
     EXPECT_EQ(0, result);
-    usleep(110000); // Sleep for longer than the update timeout.
-    EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1));
-    result = APerformanceHint_sendHint(session, hintId);
+    EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1));
+    result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint");
     EXPECT_EQ(0, result);
-    // Expect to get rate limited if we try to send faster than the limiter allows
-    EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0));
-    result = APerformanceHint_sendHint(session, hintId);
+    EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1));
+    EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1));
+    result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
     EXPECT_EQ(0, result);
 
     result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1));
     EXPECT_EQ(EINVAL, result);
 
+    Mock::VerifyAndClearExpectations(mMockSession.get());
+    for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) {
+        APerformanceHint_sendHint(session, hintId);
+    }
+
+    // Expect to get rate limited if we try to send faster than the limiter allows
+    EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
+    result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint");
+    EXPECT_EQ(result, EBUSY);
+    EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
+    result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
     EXPECT_CALL(*mMockSession, close()).Times(Exactly(1));
     APerformanceHint_closeSession(session);
 }
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 23dd9b7..4180710 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -45,8 +45,10 @@
 
     header_libs: [
         "jni_headers",
+        "native_headers",
         "libhwui_internal_headers",
     ],
+    export_header_lib_headers: ["native_headers"],
 
     static_libs: [
         "libarect",
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index a23845f..f587660 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -57,6 +57,7 @@
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable();
@@ -73,6 +74,9 @@
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+    field public static final int COMMIT_ROUTING_STATUS_FAILED = 3; // 0x3
+    field public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6; // 0x6
+    field public static final int COMMIT_ROUTING_STATUS_OK = 0; // 0x0
     field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0
     field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1
     field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3
@@ -89,13 +93,14 @@
     method public void onBootFinished(int);
     method public void onBootStarted();
     method public void onCardEmulationActivated(boolean);
-    method public void onDisable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void onDisableFinished(int);
+    method public void onDisableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void onDisableStarted();
     method public void onEeListenActivated(boolean);
-    method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void onEnableFinished(int);
+    method public void onEnableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void onEnableStarted();
+    method public void onExtractOemPackages(@NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
     method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>);
     method public void onHceEventReceived(int);
     method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String);
@@ -106,7 +111,8 @@
     method public void onReaderOptionChanged(boolean);
     method public void onRfDiscoveryStarted(boolean);
     method public void onRfFieldActivated(boolean);
-    method public void onRoutingChanged();
+    method public void onRoutingChanged(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method public void onRoutingTableFull();
     method public void onStateUpdated(int);
     method public void onTagConnected(boolean);
     method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -182,6 +188,12 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
     method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
     method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
+    method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean);
+    field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3
+    field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1
+    field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2
+    field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4
+    field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0
   }
 
 }
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 40fd068..31514a0 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -120,4 +120,5 @@
     boolean isTagPresent();
     List<Entry> getRoutingTableEntryList();
     void indicateDataMigration(boolean inProgress, String pkg);
+    int commitRouting();
 }
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 5e2e92d..633d8bf 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -47,7 +47,7 @@
     boolean unsetPreferredService();
     boolean supportsAidPrefixRegistration();
     ApduServiceInfo getPreferredPaymentService(int userHandle);
-    boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
+    int setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
     boolean isDefaultPaymentRegistered();
 
     void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
index b102e87..1a21c0b 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -41,7 +41,7 @@
    void onEnableFinished(int status);
    void onDisableFinished(int status);
    void onTagDispatch(in ResultReceiver isSkipped);
-   void onRoutingChanged();
+   void onRoutingChanged(in ResultReceiver isSkipped);
    void onHceEventReceived(int action);
    void onReaderOptionChanged(boolean enabled);
    void onCardEmulationActivated(boolean isActivated);
@@ -52,5 +52,7 @@
    void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent);
    void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category);
    void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category);
+   void onRoutingTableFull();
    void onLogEventNotified(in OemLogItems item);
+   void onExtractOemPackages(in NdefMessage message, in ResultReceiver packageReceiver);
 }
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index abd99bc..326ca64 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -23,11 +23,11 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.DurationMillisLong;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -194,6 +194,30 @@
     public @interface StatusCode {}
 
     /**
+     * Routing commit succeeded.
+     */
+    public static final int COMMIT_ROUTING_STATUS_OK = 0;
+    /**
+     * Routing commit failed.
+     */
+    public static final int COMMIT_ROUTING_STATUS_FAILED = 3;
+    /**
+     * Routing commit failed due to the update is in progress.
+     */
+    public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6;
+
+    /**
+     * Status codes returned when calling {@link #forceRoutingTableCommit()}
+     * @hide
+     */
+    @IntDef(prefix = "COMMIT_ROUTING_STATUS_", value = {
+            COMMIT_ROUTING_STATUS_OK,
+            COMMIT_ROUTING_STATUS_FAILED,
+            COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CommitRoutingStatusCode {}
+    /**
      * Interface for Oem extensions for NFC.
      */
     public interface Callback {
@@ -233,8 +257,7 @@
          *                  {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
          * false if NFC cannot be enabled at this time.
          */
-        @SuppressLint("MethodNameTense")
-        void onEnable(@NonNull Consumer<Boolean> isAllowed);
+        void onEnableRequested(@NonNull Consumer<Boolean> isAllowed);
         /**
          * Method to check if Nfc is allowed to be disabled by OEMs.
          * @param isAllowed The {@link Consumer} to be completed. If disabling NFC is allowed,
@@ -242,7 +265,7 @@
          *                  {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
          * false if NFC cannot be disabled at this time.
          */
-        void onDisable(@NonNull Consumer<Boolean> isAllowed);
+        void onDisableRequested(@NonNull Consumer<Boolean> isAllowed);
 
         /**
          * Callback to indicate that Nfc starts to boot.
@@ -255,7 +278,7 @@
         void onEnableStarted();
 
         /**
-         * Callback to indicate that Nfc starts to enable.
+         * Callback to indicate that Nfc starts to disable.
          */
         void onDisableStarted();
 
@@ -287,8 +310,12 @@
 
         /**
          * Notifies routing configuration is changed.
+         * @param isCommitRoutingSkipped The {@link Consumer} to be
+         * completed. If routing commit should be skipped,
+         * the {@link Consumer#accept(Object)} should be called with
+         * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
          */
-        void onRoutingChanged();
+        void onRoutingChanged(@NonNull Consumer<Boolean> isCommitRoutingSkipped);
 
         /**
          * API to activate start stop cpu boost on hce event.
@@ -394,10 +421,30 @@
         void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category);
 
         /**
+         * Callback to indicate that routing table is full and the OEM can optionally launch a
+         * dialog to request the user to remove some Card Emulation apps from the device to free
+         * routing table space.
+         */
+        void onRoutingTableFull();
+
+        /**
          * Callback when OEM specified log event are notified.
          * @param item the log items that contains log information of NFC event.
          */
         void onLogEventNotified(@NonNull OemLogItems item);
+
+        /**
+         * Callback to to extract OEM defined packages from given NDEF message when
+         * a NFC tag is detected. These are used to handle NFC tags encoded with a
+         * proprietary format for storing app name (Android native app format).
+         *
+         * @param message NDEF message containing OEM package names
+         * @param packageConsumer The {@link Consumer} to be completed.
+         *                        The {@link Consumer#accept(Object)} should be called with
+         *                        the list of package names.
+         */
+        void onExtractOemPackages(@NonNull NdefMessage message,
+                @NonNull Consumer<List<String>> packageConsumer);
     }
 
 
@@ -598,12 +645,12 @@
     /**
      * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
      * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
-     * use {@link #resumePolling() to resume the polling.
-     * @param timeoutInMs the pause polling duration in millisecond
+     * use {@link #resumePolling()} to resume the polling.
+     * @param timeoutInMs the pause polling duration in millisecond, ranging from 0 to 40000.
      */
     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
-    public void pausePolling(int timeoutInMs) {
+    public void pausePolling(@DurationMillisLong int timeoutInMs) {
         NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs));
     }
 
@@ -734,6 +781,18 @@
         return result;
     }
 
+    /**
+     * API to force a routing table commit.
+     * @return a {@link StatusCode} to indicate if commit routing succeeded or not
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @CommitRoutingStatusCode
+    public int forceRoutingTableCommit() {
+        return NfcAdapter.callServiceReturn(
+                () -> NfcAdapter.sService.commitRouting(), COMMIT_ROUTING_STATUS_FAILED);
+    }
+
     private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
 
         @Override
@@ -792,13 +851,13 @@
         public void onEnable(ResultReceiver isAllowed) throws RemoteException {
             mCallbackMap.forEach((cb, ex) ->
                     handleVoidCallback(
-                        new ReceiverWrapper<>(isAllowed), cb::onEnable, ex));
+                        new ReceiverWrapper<>(isAllowed), cb::onEnableRequested, ex));
         }
         @Override
         public void onDisable(ResultReceiver isAllowed) throws RemoteException {
             mCallbackMap.forEach((cb, ex) ->
                     handleVoidCallback(
-                        new ReceiverWrapper<>(isAllowed), cb::onDisable, ex));
+                        new ReceiverWrapper<>(isAllowed), cb::onDisableRequested, ex));
         }
         @Override
         public void onBootStarted() throws RemoteException {
@@ -837,9 +896,10 @@
                         new ReceiverWrapper<>(isSkipped), cb::onTagDispatch, ex));
         }
         @Override
-        public void onRoutingChanged() throws RemoteException {
+        public void onRoutingChanged(ResultReceiver isSkipped) throws RemoteException {
             mCallbackMap.forEach((cb, ex) ->
-                    handleVoidCallback(null, (Object input) -> cb.onRoutingChanged(), ex));
+                    handleVoidCallback(
+                            new ReceiverWrapper<>(isSkipped), cb::onRoutingChanged, ex));
         }
         @Override
         public void onHceEventReceived(int action) throws RemoteException {
@@ -853,6 +913,12 @@
                     handleVoidCallback(enabled, cb::onReaderOptionChanged, ex));
         }
 
+        public void onRoutingTableFull() throws RemoteException {
+            mCallbackMap.forEach((cb, ex) ->
+                    handleVoidCallback(null,
+                            (Object input) -> cb.onRoutingTableFull(), ex));
+        }
+
         @Override
         public void onGetOemAppSearchIntent(List<String> packages, ResultReceiver intentConsumer)
                 throws RemoteException {
@@ -912,6 +978,15 @@
                     handleVoidCallback(item, cb::onLogEventNotified, ex));
         }
 
+        @Override
+        public void onExtractOemPackages(NdefMessage message, ResultReceiver packageConsumer)
+                throws RemoteException {
+            mCallbackMap.forEach((cb, ex) ->
+                    handleVoid2ArgCallback(message,
+                            new ReceiverWrapper<>(packageConsumer),
+                            cb::onExtractOemPackages, ex));
+        }
+
         private <T> void handleVoidCallback(
                 T input, Consumer<T> callbackMethod, Executor executor) {
             synchronized (mLock) {
@@ -1022,8 +1097,14 @@
                 Bundle bundle = new Bundle();
                 bundle.putParcelable("intent", (Intent) result);
                 mResultReceiver.send(0, bundle);
+            } else if (result instanceof List<?> list) {
+                if (list.stream().allMatch(String.class::isInstance)) {
+                    Bundle bundle = new Bundle();
+                    bundle.putStringArray("packageNames",
+                            list.stream().map(pkg -> (String) pkg).toArray(String[]::new));
+                    mResultReceiver.send(0, bundle);
+                }
             }
-
         }
 
         @Override
diff --git a/nfc/java/android/nfc/OemLogItems.java b/nfc/java/android/nfc/OemLogItems.java
index 6671941..4f3e199 100644
--- a/nfc/java/android/nfc/OemLogItems.java
+++ b/nfc/java/android/nfc/OemLogItems.java
@@ -142,8 +142,11 @@
         dest.writeByteArray(mCommandApdus);

         dest.writeInt(mResponseApdus.length);

         dest.writeByteArray(mResponseApdus);

-        dest.writeLong(mRfFieldOnTime.getEpochSecond());

-        dest.writeInt(mRfFieldOnTime.getNano());

+        dest.writeBoolean(mRfFieldOnTime != null);

+        if (mRfFieldOnTime != null) {

+            dest.writeLong(mRfFieldOnTime.getEpochSecond());

+            dest.writeInt(mRfFieldOnTime.getNano());

+        }

         dest.writeParcelable(mTag, 0);

     }

 

@@ -305,7 +308,12 @@
         in.readByteArray(this.mCommandApdus);

         this.mResponseApdus = new byte[in.readInt()];

         in.readByteArray(this.mResponseApdus);

-        this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());

+        boolean isRfFieldOnTimeSet = in.readBoolean();

+        if (isRfFieldOnTimeSet) {

+            this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());

+        } else {

+            this.mRfFieldOnTime = null;

+        }

         this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class);

     }

 

diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index eb28c3b..8917524 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -185,6 +185,65 @@
     @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
     public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1;
 
+    /**
+     * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * succeeded.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    public static final int SET_SERVICE_ENABLED_STATUS_OK = 0;
+
+    /**
+     * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * failed due to the unsupported feature.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1;
+
+    /**
+     * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * failed due to the invalid service.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2;
+
+    /**
+     * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * failed due to the service is already set to the requested status.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3;
+
+    /**
+     * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * failed due to unknown error.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4;
+
+    /**
+     * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
+     * @hide
+     */
+    @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = {
+            SET_SERVICE_ENABLED_STATUS_OK,
+            SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED,
+            SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE,
+            SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET,
+            SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SetServiceEnabledStatusCode {}
+
     static boolean sIsInitialized = false;
     static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
     static INfcCardEmulation sService;
@@ -883,22 +942,24 @@
     }
 
     /**
-     * Allows to set or unset preferred service (category other) to avoid  AID Collision.
+     * Allows to set or unset preferred service (category other) to avoid AID Collision. The user
+     * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)}
      *
      * @param service The ComponentName of the service
      * @param status  true to enable, false to disable
-     * @param userId the user handle of the user whose information is being requested.
-     * @return set service for the category and true if service is already set return false.
+     * @return true if preferred service is successfully set or unset, otherwise return false.
      *
      * @hide
      */
-    public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status,
-                                                     int userId) {
-        if (service == null) {
-            throw new NullPointerException("activity or service or category is null");
-        }
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @SetServiceEnabledStatusCode
+    public int setServiceEnabledForCategoryOther(@NonNull ComponentName service,
+            boolean status) {
         return callServiceReturn(() ->
-                sService.setServiceEnabledForCategoryOther(userId, service, status), false);
+                sService.setServiceEnabledForCategoryOther(mContext.getUser().getIdentifier(),
+                        service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR);
     }
 
     /** @hide */
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 34f0200..8a37aa2 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -173,3 +173,11 @@
     description: "Share wallet role routing priority with associated services"
     bug: "366243361"
 }
+
+flag {
+    name: "nfc_set_service_enabled_for_category_other"
+    is_exported: true
+    namespace: "nfc"
+    description: "Enable set service enabled for category other"
+    bug: "338157113"
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b2dcb7f..a3da93d 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -61,9 +61,11 @@
         "SettingsLibUtils",
         "SettingsLibZeroStatePreference",
         "settingslib_media_flags_lib",
+    ],
+    libs:[
+        // This flag library has been added in frameworks jar
         "aconfig_settingslib_flags_java_lib",
     ],
-
     plugins: ["androidx.room_room-compiler-plugin"],
     use_resource_processor: true,
     resource_dirs: ["res"],
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
index fadcf7b..e68253e 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml
@@ -18,7 +18,7 @@
     <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="elevationOverlayEnabled">true</item>
         <item name="elevationOverlayColor">?attr/colorPrimary</item>
-        <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item>
+        <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item>
         <item name="colorAccent">@color/settingslib_materialColorPrimaryFixed</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
index 7c9d1a4..f7c9aac 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml
@@ -18,7 +18,7 @@
     <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="elevationOverlayEnabled">true</item>
         <item name="elevationOverlayColor">?attr/colorPrimary</item>
-        <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item>
+        <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item>
         <item name="colorAccent">@color/settingslib_materialColorPrimary</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
index 5ceee6d..088bef2 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
@@ -22,11 +22,13 @@
 import com.android.settingslib.ipc.ApiHandler
 import com.android.settingslib.ipc.MessageCodec
 import com.android.settingslib.metadata.PreferenceScreenRegistry
+import com.android.settingslib.preference.PreferenceScreenProvider
 import java.util.Locale
 
 /** API to get preference graph. */
-abstract class GetPreferenceGraphApiHandler :
-    ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
+abstract class GetPreferenceGraphApiHandler(
+    private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>
+) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
 
     override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
         get() = GetPreferenceGraphRequestCodec
@@ -40,14 +42,16 @@
         callingUid: Int,
         request: GetPreferenceGraphRequest,
     ): PreferenceGraphProto {
-        val builderRequest =
-            if (request.screenKeys.isEmpty()) {
-                val keys = PreferenceScreenRegistry.preferenceScreens.keys
-                GetPreferenceGraphRequest(keys, request.visitedScreens, request.locale)
-            } else {
-                request
+        val builder = PreferenceGraphBuilder.of(application, request)
+        if (request.screenKeys.isEmpty()) {
+            for (key in PreferenceScreenRegistry.preferenceScreens.keys) {
+                builder.addPreferenceScreenFromRegistry(key)
             }
-        return PreferenceGraphBuilder.of(application, builderRequest).build()
+            for (provider in preferenceScreenProviders) {
+                builder.addPreferenceScreenProvider(provider)
+            }
+        }
+        return builder.build()
     }
 }
 
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
index 2256bb3..6760e72 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -133,7 +133,7 @@
             null
         }
 
-    private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
+    suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
         val metadata = PreferenceScreenRegistry[key] ?: return false
         return addPreferenceScreenMetadata(metadata)
     }
@@ -146,7 +146,7 @@
             }
         }
 
-    private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
+    suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
         Log.d(TAG, "add $activityClass")
         createPreferenceScreen { activityClass.newInstance() }
             ?.let {
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
index 6e4db1d..7cfce0d 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
@@ -22,6 +22,7 @@
 import com.android.settingslib.graph.proto.PreferenceValueProto
 import com.android.settingslib.ipc.ApiDescriptor
 import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
 import com.android.settingslib.ipc.IntMessageCodec
 import com.android.settingslib.ipc.MessageCodec
 import com.android.settingslib.metadata.BooleanValue
@@ -45,7 +46,11 @@
     PreferenceSetterResult.OK,
     PreferenceSetterResult.UNSUPPORTED,
     PreferenceSetterResult.DISABLED,
+    PreferenceSetterResult.RESTRICTED,
     PreferenceSetterResult.UNAVAILABLE,
+    PreferenceSetterResult.REQUIRE_APP_PERMISSION,
+    PreferenceSetterResult.REQUIRE_USER_AGREEMENT,
+    PreferenceSetterResult.DISALLOW,
     PreferenceSetterResult.INVALID_REQUEST,
     PreferenceSetterResult.INTERNAL_ERROR,
 )
@@ -87,14 +92,17 @@
 }
 
 /** Preference setter API implementation. */
-class PreferenceSetterApiHandler(override val id: Int) : ApiHandler<PreferenceSetterRequest, Int> {
+class PreferenceSetterApiHandler(
+    override val id: Int,
+    private val permissionChecker: ApiPermissionChecker<PreferenceSetterRequest>,
+) : ApiHandler<PreferenceSetterRequest, Int> {
 
     override fun hasPermission(
         application: Application,
         myUid: Int,
         callingUid: Int,
         request: PreferenceSetterRequest,
-    ): Boolean = true
+    ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
 
     override suspend fun invoke(
         application: Application,
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
index d9b9590..1bda277 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
@@ -16,8 +16,10 @@
 
 package com.android.settingslib.graph
 
+import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.net.Uri
 import android.os.Bundle
 import com.android.settingslib.graph.proto.BundleProto
 import com.android.settingslib.graph.proto.BundleProto.BundleValue
@@ -42,6 +44,20 @@
     this@toProto.type?.let { mimeType = it }
 }
 
+fun IntentProto.toIntent(): Intent? {
+    if (!hasComponent()) return null
+    val componentName = ComponentName.unflattenFromString(component) ?: return null
+    val intent = Intent()
+    intent.component = componentName
+    if (hasAction()) intent.action = action
+    if (hasData()) intent.data = Uri.parse(data)
+    if (hasPkg()) intent.`package` = pkg
+    if (hasFlags()) intent.flags = flags
+    if (hasExtras()) intent.putExtras(extras.toBundle())
+    if (hasMimeType()) intent.setType(mimeType)
+    return intent
+}
+
 fun Bundle.toProto(): BundleProto = bundleProto {
     fun toProto(value: Any): BundleValue = bundleValueProto {
         when (value) {
@@ -61,14 +77,18 @@
     }
 }
 
-fun BundleValue.stringify(): String =
-    when {
-        hasBooleanValue() -> "$valueCase"
-        hasBytesValue() -> "$bytesValue"
-        hasIntValue() -> "$intValue"
-        hasLongValue() -> "$longValue"
-        hasStringValue() -> stringValue
-        hasDoubleValue() -> "$doubleValue"
-        hasBundleValue() -> "$bundleValue"
-        else -> "Unknown"
+fun BundleProto.toBundle(): Bundle =
+    Bundle().apply {
+        for ((key, value) in valuesMap) {
+            when {
+                value.hasBooleanValue() -> putBoolean(key, value.booleanValue)
+                value.hasBytesValue() -> putByteArray(key, value.bytesValue.toByteArray())
+                value.hasIntValue() -> putInt(key, value.intValue)
+                value.hasLongValue() -> putLong(key, value.longValue)
+                value.hasStringValue() -> putString(key, value.stringValue)
+                value.hasDoubleValue() -> putDouble(key, value.doubleValue)
+                value.hasBundleValue() -> putBundle(key, value.bundleValue.toBundle())
+                else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value")
+            }
+        }
     }
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
index 802141d..4febd89 100644
--- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
@@ -56,6 +56,27 @@
     val responseCodec: MessageCodec<Response>
 }
 
+/** Permission checker for api. */
+fun interface ApiPermissionChecker<R> {
+    /**
+     * Returns if the request is permitted.
+     *
+     * @param application application context
+     * @param myUid uid of current process
+     * @param callingUid uid of peer process
+     * @param request API request
+     * @return `false` if permission is denied, otherwise `true`
+     */
+    fun hasPermission(application: Application, myUid: Int, callingUid: Int, request: R): Boolean
+
+    companion object {
+        private val ALWAYS_ALLOW = ApiPermissionChecker<Any> { _, _, _, _ -> true }
+
+        @Suppress("UNCHECKED_CAST")
+        fun <T> alwaysAllow(): ApiPermissionChecker<T> = ALWAYS_ALLOW as ApiPermissionChecker<T>
+    }
+}
+
 /**
  * Handler of API.
  *
@@ -64,18 +85,8 @@
  *
  * The implementation must be threadsafe.
  */
-interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> {
-    /**
-     * Returns if the request is permitted.
-     *
-     * @return `false` if permission is denied, otherwise `true`
-     */
-    fun hasPermission(
-        application: Application,
-        myUid: Int,
-        callingUid: Int,
-        request: Request,
-    ): Boolean
+interface ApiHandler<Request, Response> :
+    ApiDescriptor<Request, Response>, ApiPermissionChecker<Request> {
 
     /**
      * Invokes the API.
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
index 7ffefed..ef907e1 100644
--- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
@@ -320,6 +320,11 @@
             }
         }
 
+        override fun onNullBinding(name: ComponentName) {
+            Log.i(TAG, "onNullBinding $name")
+            close(ClientBindServiceException(null))
+        }
+
         internal open fun drainPendingRequests() {
             disposableHandle = null
             if (pendingRequests.isEmpty()) {
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
index 6e38df1..1823ba6 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
@@ -19,9 +19,14 @@
 import android.app.Application
 import com.android.settingslib.graph.GetPreferenceGraphApiHandler
 import com.android.settingslib.graph.GetPreferenceGraphRequest
+import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.preference.PreferenceScreenProvider
 
 /** Api to get preference graph. */
-internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() {
+internal class PreferenceGraphApi(
+    preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>,
+    private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>,
+) : GetPreferenceGraphApiHandler(preferenceScreenProviders) {
 
     override val id: Int
         get() = API_GET_PREFERENCE_GRAPH
@@ -31,5 +36,5 @@
         myUid: Int,
         callingUid: Int,
         request: GetPreferenceGraphRequest,
-    ) = true
+    ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
 }
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
index 8ebb145..ed748bb 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
@@ -16,10 +16,14 @@
 
 package com.android.settingslib.service
 
+import com.android.settingslib.graph.GetPreferenceGraphRequest
 import com.android.settingslib.graph.PreferenceSetterApiHandler
+import com.android.settingslib.graph.PreferenceSetterRequest
 import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
 import com.android.settingslib.ipc.MessengerService
 import com.android.settingslib.ipc.PermissionChecker
+import com.android.settingslib.preference.PreferenceScreenProvider
 
 /**
  * Preference service providing a bunch of APIs.
@@ -28,14 +32,21 @@
  * [PREFERENCE_SERVICE_ACTION].
  */
 open class PreferenceService(
-    permissionChecker: PermissionChecker,
     name: String = "PreferenceService",
+    permissionChecker: PermissionChecker = PermissionChecker { _, _, _ -> true },
+    preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> = setOf(),
+    graphPermissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>? = null,
+    setterPermissionChecker: ApiPermissionChecker<PreferenceSetterRequest>? = null,
+    vararg apiHandlers: ApiHandler<*, *>,
 ) :
     MessengerService(
-        listOf<ApiHandler<*, *>>(
-            PreferenceGraphApi(),
-            PreferenceSetterApiHandler(API_PREFERENCE_SETTER),
-        ),
+        mutableListOf<ApiHandler<*, *>>().apply {
+            graphPermissionChecker?.let { add(PreferenceGraphApi(preferenceScreenProviders, it)) }
+            setterPermissionChecker?.let {
+                add(PreferenceSetterApiHandler(API_PREFERENCE_SETTER, it))
+            }
+            addAll(apiHandlers)
+        },
         permissionChecker,
         name,
     )
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
index 1f38a66..7655daa 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
@@ -18,5 +18,14 @@
 
 const val PREFERENCE_SERVICE_ACTION = "com.android.settingslib.PREFERENCE_SERVICE"
 
+/** API id for retrieving preference graph. */
 internal const val API_GET_PREFERENCE_GRAPH = 1
+
+/** API id for preference value setter. */
 internal const val API_PREFERENCE_SETTER = 2
+
+/**
+ * The max API id reserved for internal preference service usages. Custom API id should start with
+ * **1000** to avoid conflict.
+ */
+internal const val API_MAX_RESERVED = 999
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
index b46181e..8b574aa 100644
--- a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in light theme	-->
+<!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in light theme	-->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
 </selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 313748d..46ec62e 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -51,7 +51,7 @@
 
     <color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_100</color>
 
-    <!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in dark theme	-->
+    <!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in dark theme	-->
     <color name="settingslib_surface_dark">@android:color/system_neutral1_800</color>
 
     <!--Deprecated. After sdk 35, don't use it-->
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
index 94ff02d..84a3ed6 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml
@@ -53,11 +53,11 @@
     <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color>
     <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color>
     <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color>
-    <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_light</color>
+    <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_light</color>
     <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color>
     <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color>
-    <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_light</color>
-    <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_light</color>
+    <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_light</color>
+    <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_light</color>
     <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color>
     <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color>
     <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index b99ee51..fef92b7 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -67,9 +67,9 @@
     <color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
     <!--Deprecated. After sdk 35 don't use it.-->
     <color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
-    <!--Deprecated. After sdk 35 don't use it.using materialColorOnSurfaceInverse in dark theme-->
+    <!--Deprecated. After sdk 35 don't use it.using materialColorInverseOnSurface in dark theme-->
     <color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
-    <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurfaceInverse in light theme-->
+    <!--Deprecated. After sdk 35 don't use it. using materialColorInverseOnSurface in light theme-->
     <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
     <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurface-->
     <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
index 8b95016..90c19e1 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml
@@ -66,16 +66,16 @@
     <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color>
     <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color>
     <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color>
-    <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_dark</color>
+    <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_dark</color>
     <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color>
     <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color>
     <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color>
     <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color>
     <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color>
     <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color>
-    <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_dark</color>
+    <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_dark</color>
     <color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color>
-    <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_dark</color>
+    <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_dark</color>
     <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color>
     <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color>
     <color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color>
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
index 4d3a78a5..f2bc380 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt
@@ -17,8 +17,12 @@
 package com.android.settingslib.spa.gallery.ui
 
 import android.os.Bundle
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.height
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
 import com.android.settingslib.spa.framework.common.SettingsEntry
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -30,6 +34,7 @@
 import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 import com.android.settingslib.spa.widget.ui.Category
+import com.android.settingslib.spa.widget.ui.LazyCategory
 
 private const val TITLE = "Sample Category"
 
@@ -65,7 +70,7 @@
         )
         entryList.add(
             SettingsEntryBuilder.create("Preference 3", owner)
-                .setMacro { SimplePreferenceMacro(title = "Preference 2", summary = "Summary 3") }
+                .setMacro { SimplePreferenceMacro(title = "Preference 3", summary = "Summary 3") }
                 .build()
         )
         entryList.add(
@@ -88,6 +93,13 @@
                 entries[2].UiLayout()
                 entries[3].UiLayout()
             }
+            Column(Modifier.height(200.dp)) {
+                LazyCategory(
+                    list = entries,
+                    entry = { index: Int -> @Composable { entries[index].UiLayout() } },
+                    title = { index: Int -> if (index == 0 || index == 2) "LazyCategory" else null },
+                ) {}
+            }
         }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
index 66680fa..28b2b4a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt
@@ -19,8 +19,13 @@
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.rememberLazyListState
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.TouchApp
 import androidx.compose.material3.MaterialTheme
@@ -34,6 +39,7 @@
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsShape
@@ -98,6 +104,57 @@
     }
 }
 
+/**
+ * A container that is used to group items with lazy loading.
+ *
+ * @param list The list of items to display.
+ * @param entry The entry for each list item according to its index in list.
+ * @param key Optional. The key for each item in list to provide unique item identifiers, making
+ * the list more efficient.
+ * @param title Optional. Category title for each item or each group of items in the list. It
+ * should be decided by the index.
+ * @param bottomPadding Optional. Bottom outside padding of the category.
+ * @param state Optional. State of LazyList.
+ * @param content Optional. Content to be shown at the top of the category.
+ */
+
+@Composable
+fun LazyCategory(
+    list: List<Any>,
+    entry: (Int) -> @Composable () -> Unit,
+    key: ((Int) -> Any)? = null,
+    title: ((Int) -> String?)? = null,
+    bottomPadding: Dp = SettingsDimension.paddingSmall,
+    state: LazyListState = rememberLazyListState(),
+    content: @Composable () -> Unit,
+) {
+    Column(
+        Modifier.padding(
+                PaddingValues(
+                    start = SettingsDimension.paddingLarge,
+                    end = SettingsDimension.paddingLarge,
+                    top = SettingsDimension.paddingSmall,
+                    bottom = bottomPadding,
+                )
+            )
+            .clip(SettingsShape.CornerMedium2)
+    ) {
+        LazyColumn(
+            modifier = Modifier.fillMaxSize(),
+            verticalArrangement = Arrangement.spacedBy(SettingsDimension.paddingTiny),
+            state = state,
+        ) {
+            item { content() }
+
+            items(count = list.size, key = key) {
+                title?.invoke(it)?.let { title -> CategoryTitle(title) }
+                val entryPreference = entry(it)
+                entryPreference()
+            }
+        }
+    }
+}
+
 @Preview
 @Composable
 private fun CategoryPreview() {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
index 09a6e6d..4b4a8c2 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/CategoryTest.kt
@@ -16,10 +16,16 @@
 
 package com.android.settingslib.spa.widget.ui
 
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.height
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -30,14 +36,11 @@
 @RunWith(AndroidJUnit4::class)
 class CategoryTest {
 
-    @get:Rule
-    val composeTestRule = createComposeRule()
+    @get:Rule val composeTestRule = createComposeRule()
 
     @Test
     fun categoryTitle() {
-        composeTestRule.setContent {
-            CategoryTitle(title = "CategoryTitle")
-        }
+        composeTestRule.setContent { CategoryTitle(title = "CategoryTitle") }
 
         composeTestRule.onNodeWithText("CategoryTitle").assertIsDisplayed()
     }
@@ -46,12 +49,14 @@
     fun category_hasContent_titleDisplayed() {
         composeTestRule.setContent {
             Category(title = "CategoryTitle") {
-                Preference(remember {
-                    object : PreferenceModel {
-                        override val title = "Some Preference"
-                        override val summary = { "Some summary" }
+                Preference(
+                    remember {
+                        object : PreferenceModel {
+                            override val title = "Some Preference"
+                            override val summary = { "Some summary" }
+                        }
                     }
-                })
+                )
             }
         }
 
@@ -60,10 +65,45 @@
 
     @Test
     fun category_noContent_titleNotDisplayed() {
-        composeTestRule.setContent {
-            Category(title = "CategoryTitle") {}
-        }
+        composeTestRule.setContent { Category(title = "CategoryTitle") {} }
 
         composeTestRule.onNodeWithText("CategoryTitle").assertDoesNotExist()
     }
+
+    @Test
+    fun lazyCategory_content_displayed() {
+        composeTestRule.setContent { TestLazyCategory() }
+
+        composeTestRule.onNodeWithText("text").assertExists()
+    }
+
+    @Test
+    fun lazyCategory_title_displayed() {
+        composeTestRule.setContent { TestLazyCategory() }
+
+        composeTestRule.onNodeWithText("LazyCategory 0").assertExists()
+        composeTestRule.onNodeWithText("LazyCategory 1").assertDoesNotExist()
+    }
+}
+
+@Composable
+private fun TestLazyCategory() {
+    val list: List<PreferenceModel> =
+        listOf(
+            object : PreferenceModel {
+                override val title = "title"
+            },
+            object : PreferenceModel {
+                override val title = "title"
+            },
+        )
+    Column(Modifier.height(200.dp)) {
+        LazyCategory(
+            list = list,
+            entry = { index: Int -> @Composable { Preference(list[index]) } },
+            title = { index: Int -> if (index == 0) "LazyCategory $index" else null },
+        ) {
+            Text("text")
+        }
+    }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index bededf0..2a214b6 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -37,7 +37,9 @@
 import com.android.settingslib.spa.framework.compose.LogCompositions
 import com.android.settingslib.spa.framework.compose.TimeMeasurer.Companion.rememberTimeMeasurer
 import com.android.settingslib.spa.framework.compose.rememberLazyListStateAndHideKeyboardWhenStartScroll
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
 import com.android.settingslib.spa.widget.ui.CategoryTitle
+import com.android.settingslib.spa.widget.ui.LazyCategory
 import com.android.settingslib.spa.widget.ui.PlaceholderTitle
 import com.android.settingslib.spa.widget.ui.Spinner
 import com.android.settingslib.spa.widget.ui.SpinnerOption
@@ -55,19 +57,14 @@
 private const val TAG = "AppList"
 private const val CONTENT_TYPE_HEADER = "header"
 
-/**
- * The config used to load the App List.
- */
+/** The config used to load the App List. */
 data class AppListConfig(
     val userIds: List<Int>,
     val showInstantApps: Boolean,
     val matchAnyUserForAdmin: Boolean,
 )
 
-data class AppListState(
-    val showSystem: () -> Boolean,
-    val searchQuery: () -> String,
-)
+data class AppListState(val showSystem: () -> Boolean, val searchQuery: () -> String)
 
 data class AppListInput<T : AppRecord>(
     val config: AppListConfig,
@@ -90,7 +87,7 @@
 
 @Composable
 internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
-    viewModelSupplier: @Composable () -> IAppListViewModel<T>,
+    viewModelSupplier: @Composable () -> IAppListViewModel<T>
 ) {
     LogCompositions(TAG, config.userIds.toString())
     val viewModel = viewModelSupplier()
@@ -125,7 +122,7 @@
     appListData: State<AppListData<T>?>,
     header: @Composable () -> Unit,
     bottomPadding: Dp,
-    noItemMessage: String?
+    noItemMessage: String?,
 ) {
     val timeMeasurer = rememberTimeMeasurer(TAG)
     appListData.value?.let { (list, option) ->
@@ -135,40 +132,61 @@
             PlaceholderTitle(noItemMessage ?: stringResource(R.string.no_applications))
             return
         }
-        LazyColumn(
-            modifier = Modifier.fillMaxSize(),
-            state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
-            contentPadding = PaddingValues(bottom = bottomPadding),
-        ) {
-            item(contentType = CONTENT_TYPE_HEADER) {
+        if (isSpaExpressiveEnabled) {
+            LazyCategory(
+                list = list,
+                entry = { index: Int ->
+                    @Composable {
+                        val appEntry = list[index]
+                        val summary = getSummary(option, appEntry.record) ?: { "" }
+                        remember(appEntry) {
+                                AppListItemModel(appEntry.record, appEntry.label, summary)
+                            }
+                            .AppItem()
+                    }
+                },
+                key = { index: Int -> list[index].record.itemKey(option) },
+                title = { index: Int -> getGroupTitle(option, list[index].record) },
+                bottomPadding = bottomPadding,
+                state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
+            ) {
                 header()
             }
+        } else {
+            LazyColumn(
+                modifier = Modifier.fillMaxSize(),
+                state = rememberLazyListStateAndHideKeyboardWhenStartScroll(),
+                contentPadding = PaddingValues(bottom = bottomPadding),
+            ) {
+                item(contentType = CONTENT_TYPE_HEADER) { header() }
 
-            items(count = list.size, key = { list[it].record.itemKey(option) }) {
-                remember(list) { getGroupTitleIfFirst(option, list, it) }
-                    ?.let { group -> CategoryTitle(title = group) }
+                items(count = list.size, key = { list[it].record.itemKey(option) }) {
+                    remember(list) { getGroupTitleIfFirst(option, list, it) }
+                        ?.let { group -> CategoryTitle(title = group) }
 
-                val appEntry = list[it]
-                val summary = getSummary(option, appEntry.record) ?: { "" }
-                remember(appEntry) {
-                    AppListItemModel(appEntry.record, appEntry.label, summary)
-                }.AppItem()
+                    val appEntry = list[it]
+                    val summary = getSummary(option, appEntry.record) ?: { "" }
+                    remember(appEntry) {
+                            AppListItemModel(appEntry.record, appEntry.label, summary)
+                        }
+                        .AppItem()
+                }
             }
         }
     }
 }
 
-private fun <T : AppRecord> T.itemKey(option: Int) =
-    listOf(option, app.packageName, app.userId)
+private fun <T : AppRecord> T.itemKey(option: Int) = listOf(option, app.packageName, app.userId)
 
 /** Returns group title if this is the first item of the group. */
 private fun <T : AppRecord> AppListModel<T>.getGroupTitleIfFirst(
     option: Int,
     list: List<AppEntry<T>>,
     index: Int,
-): String? = getGroupTitle(option, list[index].record)?.takeIf {
-    index == 0 || it != getGroupTitle(option, list[index - 1].record)
-}
+): String? =
+    getGroupTitle(option, list[index].record)?.takeIf {
+        index == 0 || it != getGroupTitle(option, list[index - 1].record)
+    }
 
 @Composable
 private fun <T : AppRecord> rememberViewModel(
@@ -183,16 +201,19 @@
     viewModel.searchQuery.Sync(state.searchQuery)
 
     LifecycleEffect(onStart = { viewModel.reloadApps() })
-    val intentFilter = IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
-        addAction(Intent.ACTION_PACKAGE_REMOVED)
-        addAction(Intent.ACTION_PACKAGE_CHANGED)
-        addDataScheme("package")
-    }
+    val intentFilter =
+        IntentFilter(Intent.ACTION_PACKAGE_ADDED).apply {
+            addAction(Intent.ACTION_PACKAGE_REMOVED)
+            addAction(Intent.ACTION_PACKAGE_CHANGED)
+            addDataScheme("package")
+        }
     for (userId in config.userIds) {
         DisposableBroadcastReceiverAsUser(
             intentFilter = intentFilter,
             userHandle = UserHandle.of(userId),
-        ) { viewModel.reloadApps() }
+        ) {
+            viewModel.reloadApps()
+        }
     }
     return viewModel
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index a87b815..216574a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,6 +1,7 @@
 package com.android.settingslib.bluetooth;
 
 import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.UNKNOWN_VALUE_PLACEHOLDER;
+import static com.android.settingslib.flags.Flags.audioSharingHysteresisModeFix;
 import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_ADVANCED;
 
 import android.annotation.SuppressLint;
@@ -651,6 +652,13 @@
                 context.getContentResolver()));
     }
 
+    /** Returns if the le audio sharing hysteresis mode fix is available. */
+    @WorkerThread
+    public static boolean isAudioSharingHysteresisModeFixAvailable(@Nullable Context context) {
+        return (audioSharingHysteresisModeFix() && Flags.enableLeAudioSharing())
+                || (context != null && isAudioSharingPreviewEnabled(context.getContentResolver()));
+    }
+
     /** Returns if the le audio sharing is enabled. */
     public static boolean isAudioSharingEnabled() {
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -733,13 +741,15 @@
     @WorkerThread
     public static boolean hasConnectedBroadcastSourceForBtDevice(
             @Nullable BluetoothDevice device, @Nullable LocalBluetoothManager localBtManager) {
-        if (Flags.audioSharingHysteresisModeFix()) {
+        if (localBtManager == null) {
+            Log.d(TAG, "Skip check hasConnectedBroadcastSourceForBtDevice due to arg is null");
+            return false;
+        }
+        if (isAudioSharingHysteresisModeFixAvailable(localBtManager.getContext())) {
             return hasActiveLocalBroadcastSourceForBtDevice(device, localBtManager);
         }
         LocalBluetoothLeBroadcastAssistant assistant =
-                localBtManager == null
-                        ? null
-                        : localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+                localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
         if (device == null || assistant == null) {
             Log.d(TAG, "Skip check hasConnectedBroadcastSourceForBtDevice due to arg is null");
             return false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 6a9d568..dc52b4d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -18,6 +18,8 @@
 
 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
 
+import static com.android.settingslib.Utils.isAudioModeOngoingCall;
+
 import static java.util.stream.Collectors.toList;
 
 import android.annotation.CallbackExecutor;
@@ -54,7 +56,6 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.settingslib.R;
-import com.android.settingslib.flags.Flags;
 
 import com.google.common.collect.ImmutableList;
 
@@ -303,6 +304,7 @@
                                         + ", sourceId = "
                                         + sourceId);
                     }
+                    updateFallbackActiveDeviceIfNeeded();
                 }
 
                 @Override
@@ -390,9 +392,6 @@
                                         + ", state = "
                                         + state);
                     }
-                    if (BluetoothUtils.isConnected(state)) {
-                        updateFallbackActiveDeviceIfNeeded();
-                    }
                 }
             };
 
@@ -1130,18 +1129,8 @@
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded for work profile.");
             return;
         }
-        if (mServiceBroadcast == null) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to broadcast profile is null");
-            return;
-        }
-        List<BluetoothLeBroadcastMetadata> sources = mServiceBroadcast.getAllBroadcastMetadata();
-        if (sources.stream()
-                .noneMatch(source -> mServiceBroadcast.isPlaying(source.getBroadcastId()))) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no broadcast ongoing");
-            return;
-        }
-        if (mServiceBroadcastAssistant == null) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
+        if (isAudioModeOngoingCall(mContext)) {
+            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to ongoing call");
             return;
         }
         Map<Integer, List<BluetoothDevice>> deviceGroupsInBroadcast = getDeviceGroupsInBroadcast();
@@ -1152,7 +1141,7 @@
         int targetGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
         int fallbackActiveGroupId = BluetoothUtils.getPrimaryGroupIdForBroadcast(
                 mContext.getContentResolver());
-        if (Flags.audioSharingHysteresisModeFix()) {
+        if (BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)) {
             int userPreferredPrimaryGroupId = getUserPreferredPrimaryGroupId();
             if (userPreferredPrimaryGroupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
                     && deviceGroupsInBroadcast.containsKey(userPreferredPrimaryGroupId)) {
@@ -1193,7 +1182,8 @@
 
     @NonNull
     private Map<Integer, List<BluetoothDevice>> getDeviceGroupsInBroadcast() {
-        boolean hysteresisModeFixEnabled = Flags.audioSharingHysteresisModeFix();
+        boolean hysteresisModeFixEnabled =
+                BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext);
         List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices();
         return connectedDevices.stream()
                 .filter(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
index 91a99ae..a0a6d26 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistantCallbackExt.kt
@@ -35,11 +35,7 @@
                     sink: BluetoothDevice,
                     sourceId: Int,
                     state: BluetoothLeBroadcastReceiveState
-                ) {
-                    if (BluetoothUtils.isConnected(state)) {
-                        launch { send(Unit) }
-                    }
-                }
+                ) {}
 
                 override fun onSourceRemoved(sink: BluetoothDevice, sourceId: Int, reason: Int) {
                     launch { send(Unit) }
@@ -55,7 +51,9 @@
 
                 override fun onSourceFound(source: BluetoothLeBroadcastMetadata) {}
 
-                override fun onSourceAdded(sink: BluetoothDevice, sourceId: Int, reason: Int) {}
+                override fun onSourceAdded(sink: BluetoothDevice, sourceId: Int, reason: Int) {
+                    launch { send(Unit) }
+                }
 
                 override fun onSourceAddFailed(
                     sink: BluetoothDevice,
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
index 83ee975..80e5e59 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java
@@ -15,6 +15,7 @@
  */
 package com.android.settingslib.media;
 
+import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET;
 import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
 import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
@@ -103,7 +104,8 @@
                             TYPE_USB_DEVICE,
                             TYPE_USB_HEADSET,
                             TYPE_USB_ACCESSORY,
-                            TYPE_BLUETOOTH_SCO ->
+                            TYPE_BLUETOOTH_SCO,
+                            TYPE_BLE_HEADSET ->
                     true;
             default -> false;
         };
@@ -124,7 +126,7 @@
                     mProductName != null
                             ? mProductName
                             : mContext.getString(R.string.media_transfer_usb_device_mic_name);
-            case TYPE_BLUETOOTH_SCO ->
+            case TYPE_BLUETOOTH_SCO, TYPE_BLE_HEADSET ->
                     mProductName != null
                             ? mProductName
                             : mContext.getString(R.string.media_transfer_bt_device_mic_name);
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
index 5eeb49a..6842d0a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java
@@ -204,6 +204,13 @@
         return this;
     }
 
+    public TestModeBuilder implicitForPackage(String pkg) {
+        setPackage(pkg);
+        setId(ZenModeConfig.implicitRuleId(pkg));
+        setName("Do Not Disturb (" + pkg + ")");
+        return this;
+    }
+
     public TestModeBuilder setActive(boolean active) {
         if (active) {
             mConfigZenRule.enabled = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 3cc111f..d5cfe55 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -24,7 +24,6 @@
 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleEvent;
 import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleTime;
-import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;
 import static android.service.notification.ZenModeConfig.tryParseEventConditionId;
 import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;
 
@@ -209,6 +208,11 @@
     }
 
     @NonNull
+    public Kind getKind() {
+        return mKind;
+    }
+
+    @NonNull
     public Status getStatus() {
         return mStatus;
     }
@@ -225,27 +229,6 @@
     }
 
     /**
-     * Returns a "dynamic" trigger description. For some modes (such as manual Do Not Disturb)
-     * when activated, we know when (and if) the mode is expected to end on its own; this dynamic
-     * description reflects that. In other cases, returns {@link #getTriggerDescription}.
-     */
-    @Nullable
-    public String getDynamicDescription(Context context) {
-        if (isManualDnd() && isActive()) {
-            long countdownEndTime = tryParseCountdownConditionId(mRule.getConditionId());
-            if (countdownEndTime > 0) {
-                CharSequence formattedTime = ZenModeConfig.getFormattedTime(context,
-                        countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
-                        context.getUserId());
-                return context.getString(com.android.internal.R.string.zen_mode_until,
-                        formattedTime);
-            }
-        }
-
-        return getTriggerDescription();
-    }
-
-    /**
      * Returns the {@link ZenIcon.Key} corresponding to the icon resource for this mode. This can be
      * either app-provided (via {@link AutomaticZenRule#setIconResId}, user-chosen (via the icon
      * picker in Settings), or a default icon based on the mode {@link Kind} and {@link #getType}.
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
new file mode 100644
index 0000000..f577698
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.notification.modes;
+
+import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.service.notification.ZenModeConfig.tryParseCountdownConditionId;
+
+import android.content.Context;
+import android.service.notification.SystemZenRules;
+import android.service.notification.ZenModeConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.google.common.base.Strings;
+
+public final class ZenModeDescriptions {
+
+    private final Context mContext;
+
+    public ZenModeDescriptions(@NonNull Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Returns a version of the mode's trigger description that might be "dynamic".
+     *
+     * <p>For some modes (such as manual Do Not Disturb) when activated, we know when (and if) the
+     * mode is expected to end on its own; this description reflects that. In other cases,
+     * returns {@link ZenMode#getTriggerDescription}.
+     */
+    @Nullable
+    public String getTriggerDescription(@NonNull ZenMode mode) {
+        if (mode.isManualDnd() && mode.isActive()) {
+            long countdownEndTime = tryParseCountdownConditionId(mode.getRule().getConditionId());
+            if (countdownEndTime > 0) {
+                CharSequence formattedTime = ZenModeConfig.getFormattedTime(mContext,
+                        countdownEndTime, ZenModeConfig.isToday(countdownEndTime),
+                        mContext.getUserId());
+                return mContext.getString(com.android.internal.R.string.zen_mode_until,
+                        formattedTime);
+            }
+        }
+
+        return Strings.emptyToNull(mode.getTriggerDescription());
+    }
+
+    /**
+     * Returns a version of the {@link ZenMode} trigger description that is suitable for
+     * accessibility (for example, where abbreviations are expanded to full words).
+     *
+     * <p>Returns {@code null} If the standard trigger description (returned by
+     * {@link #getTriggerDescription}) is sufficient.
+     */
+    @Nullable
+    public String getTriggerDescriptionForAccessibility(@NonNull ZenMode mode) {
+        // Only one special case: time-based schedules, where we want to use full day names.
+        if (mode.isSystemOwned() && mode.getType() == TYPE_SCHEDULE_TIME) {
+            ZenModeConfig.ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(
+                    mode.getRule().getConditionId());
+            if (schedule != null) {
+                String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule);
+                if (fullDaysSummary != null) {
+                    return fullDaysSummary + ", " + SystemZenRules.getTimeSummary(mContext,
+                            schedule);
+                }
+            }
+        }
+
+        return null;
+    }
+}
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 6d481db..fa5d542 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
@@ -1256,4 +1256,40 @@
 
         assertThat(BluetoothUtils.isAudioSharingUIAvailable(mContext)).isTrue();
     }
+
+    @Test
+    public void isAudioSharingHysteresisModeFixAvailable_mainAndPreviewFlagOff_returnsFalse() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+        assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isFalse();
+    }
+
+    @Test
+    public void isAudioSharingHysteresisModeFixAvailable_hysteresisFixFlagOff_returnsFalse() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+        assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isFalse();
+    }
+
+    @Test
+    public void isAudioSharingHysteresisModeFixAvailable_previewFlagOn_returnsTrue() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+        assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isTrue();
+    }
+
+    @Test
+    public void isAudioSharingHysteresisModeFixAvailable_mainAndPreviewFlagOn_returnsTrue() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
+        mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_DEVELOPER_OPTION);
+
+        assertThat(BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext)).isTrue();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
index 7775b91..8624c4d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java
@@ -38,6 +38,7 @@
     private final int WIRED_HEADSET_ID = 2;
     private final int USB_HEADSET_ID = 3;
     private final int BT_HEADSET_ID = 4;
+    private final int BLE_HEADSET_ID = 5;
     private final int MAX_VOLUME = 1;
     private final int CURRENT_VOLUME = 0;
     private final boolean IS_VOLUME_FIXED = true;
@@ -45,6 +46,7 @@
     private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset";
     private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset";
     private static final String PRODUCT_NAME_BT_HEADSET = "My Bluetooth Headset";
+    private static final String PRODUCT_NAME_BLE_HEADSET = "My BLE Headset";
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -163,4 +165,35 @@
         assertThat(btMediaDevice.getName())
                 .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name));
     }
+
+    @Test
+    public void getName_returnCorrectName_bleHeadset() {
+        InputMediaDevice bleMediaDevice =
+                InputMediaDevice.create(
+                        mContext,
+                        String.valueOf(BLE_HEADSET_ID),
+                        AudioDeviceInfo.TYPE_BLE_HEADSET,
+                        MAX_VOLUME,
+                        CURRENT_VOLUME,
+                        IS_VOLUME_FIXED,
+                        PRODUCT_NAME_BLE_HEADSET);
+        assertThat(bleMediaDevice).isNotNull();
+        assertThat(bleMediaDevice.getName()).isEqualTo(PRODUCT_NAME_BLE_HEADSET);
+    }
+
+    @Test
+    public void getName_returnCorrectName_bleHeadset_nullProductName() {
+        InputMediaDevice bleMediaDevice =
+                InputMediaDevice.create(
+                        mContext,
+                        String.valueOf(BLE_HEADSET_ID),
+                        AudioDeviceInfo.TYPE_BLE_HEADSET,
+                        MAX_VOLUME,
+                        CURRENT_VOLUME,
+                        IS_VOLUME_FIXED,
+                        null);
+        assertThat(bleMediaDevice).isNotNull();
+        assertThat(bleMediaDevice.getName())
+                .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name));
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java
new file mode 100644
index 0000000..2b3accd
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeDescriptionsTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.settingslib.notification.modes;
+
+import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.service.notification.SystemZenRules.PACKAGE_ANDROID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.service.notification.ZenModeConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Calendar;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenModeDescriptionsTest {
+
+    private final ZenModeDescriptions mDescriptions = new ZenModeDescriptions(
+            RuntimeEnvironment.getApplication());
+
+    @Test
+    public void getTriggerDescriptionForAccessibility_scheduleTime_usesFullDays() {
+        ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
+        scheduleInfo.days = new int[] { Calendar.MONDAY };
+        scheduleInfo.startHour = 11;
+        scheduleInfo.endHour = 15;
+        ZenMode mode = new TestModeBuilder()
+                .setPackage(PACKAGE_ANDROID)
+                .setType(TYPE_SCHEDULE_TIME)
+                .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+                .build();
+
+        assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode))
+                .isEqualTo("Monday, 11:00 AM - 3:00 PM");
+    }
+
+    @Test
+    public void getTriggerDescriptionForAccessibility_otherMode_isNull() {
+        ZenMode mode = new TestModeBuilder().setTriggerDescription("When December ends").build();
+        assertThat(mDescriptions.getTriggerDescriptionForAccessibility(mode)).isNull();
+    }
+}
diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml
index 22d0226..645b275 100644
--- a/packages/SettingsProvider/res/xml/bookmarks.xml
+++ b/packages/SettingsProvider/res/xml/bookmarks.xml
@@ -32,6 +32,9 @@
        'y': YouTube
 -->
 <bookmarks>
+    <!-- TODO(b/358569822): Remove this from Settings DB
+         This is legacy implementation to store bookmarks in Settings DB, which is deprecated and
+         no longer used -->
     <bookmark
         role="android.app.role.BROWSER"
         shortcut="b" />
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7b6321d..526320d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -369,6 +369,9 @@
     <!-- Permission needed for CTS test - UnsupportedErrorDialogTests -->
     <uses-permission android:name="android.permission.RESET_APP_ERRORS" />
 
+    <!-- Permission needed tests -->
+    <uses-permission android:name="android.permission.OBSERVE_PICTURE_PROFILES" />
+
     <!-- Permission needed for CTS test - CtsSystemUiTestCases:PipNotificationTests -->
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
@@ -953,6 +956,13 @@
     <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE"
         android:featureFlag="android.security.aapm_api"/>
 
+    <!-- Permission required for CTS test - ForensicManagerTest -->
+    <uses-permission android:name="android.permission.READ_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"/>
+    <uses-permission android:name="android.permission.MANAGE_FORENSIC_STATE"
+        android:featureFlag="android.security.afl_api"/>
+
+
     <!-- Permission required for CTS test - CtsAppTestCases -->
     <uses-permission android:name="android.permission.KILL_UID" />
 
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 8feefa5..d4b5b862 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -12,3 +12,4 @@
 cbrubaker@google.com
 omakoto@google.com
 michaelwr@google.com
+ronish@google.com
diff --git a/packages/Shell/aconfig/Android.bp b/packages/Shell/aconfig/Android.bp
new file mode 100644
index 0000000..1d797b2
--- /dev/null
+++ b/packages/Shell/aconfig/Android.bp
@@ -0,0 +1,13 @@
+aconfig_declarations {
+    name: "wear_aconfig_declarations",
+    package: "com.android.shell.flags",
+    container: "system",
+    srcs: [
+        "wear.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "wear_aconfig_declarations_flags_java_lib",
+    aconfig_declarations: "wear_aconfig_declarations",
+}
diff --git a/packages/Shell/aconfig/wear.aconfig b/packages/Shell/aconfig/wear.aconfig
new file mode 100644
index 0000000..e07bd96
--- /dev/null
+++ b/packages/Shell/aconfig/wear.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.shell.flags"
+container: "system"
+
+flag {
+    name: "handle_bugreports_for_wear"
+    namespace: "wear_services"
+    description: "This flag enables Shell to propagate bugreport results to WearServices."
+    bug: "378060870"
+}
\ No newline at end of file
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 7c478ac..7f25b51 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -153,6 +153,10 @@
     static final String INTENT_BUGREPORT_FINISHED =
             "com.android.internal.intent.action.BUGREPORT_FINISHED";
 
+    // Intent sent to notify external apps that bugreport aborted due to error.
+    static final String INTENT_BUGREPORT_ABORTED =
+            "com.android.internal.intent.action.BUGREPORT_ABORTED";
+
     // Internal intents used on notification actions.
     static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
     static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
@@ -174,6 +178,8 @@
     static final String EXTRA_INFO = "android.intent.extra.INFO";
     static final String EXTRA_EXTRA_ATTACHMENT_URIS =
             "android.intent.extra.EXTRA_ATTACHMENT_URIS";
+    static final String EXTRA_ABORTED_ERROR_CODE =
+            "android.intent.extra.EXTRA_ABORTED_ERROR_CODE";
 
     private static final ThreadFactory sBugreportManagerCallbackThreadFactory =
             new ThreadFactory() {
@@ -404,6 +410,7 @@
         @Override
         public void onError(@BugreportErrorCode int errorCode) {
             synchronized (mLock) {
+                sendBugreportAbortedBroadcastLocked(errorCode);
                 stopProgressLocked(mInfo.id);
                 mInfo.deleteEmptyFiles();
             }
@@ -460,6 +467,13 @@
                 onBugreportFinished(mInfo);
             }
         }
+
+        @GuardedBy("mLock")
+        private void sendBugreportAbortedBroadcastLocked(@BugreportErrorCode int errorCode) {
+            final Intent intent = new Intent(INTENT_BUGREPORT_ABORTED);
+            intent.putExtra(EXTRA_ABORTED_ERROR_CODE, errorCode);
+            mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
+        }
     }
 
     private void sendRemoteBugreportFinishedBroadcast(Context context,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index bffda8b..dafe38d 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -90,8 +90,6 @@
         "tests/src/**/systemui/globalactions/GlobalActionsDialogLiteTest.java",
         "tests/src/**/systemui/globalactions/GlobalActionsImeTest.java",
         "tests/src/**/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
         "tests/src/**/systemui/media/dialog/MediaOutputAdapterTest.java",
         "tests/src/**/systemui/media/dialog/MediaOutputBaseDialogTest.java",
         "tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
@@ -134,7 +132,6 @@
         "tests/src/**/systemui/accessibility/floatingmenu/MenuViewLayerTest.java",
         "tests/src/**/systemui/accessibility/floatingmenu/MenuViewTest.java",
         "tests/src/**/systemui/classifier/PointerCountClassifierTest.java",
-        "tests/src/**/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt",
         "tests/src/**/systemui/accessibility/floatingmenu/RadiiAnimatorTest.java",
         "tests/src/**/systemui/screenrecord/RecordingControllerTest.java",
         "tests/src/**/systemui/screenshot/RequestProcessorTest.kt",
@@ -216,8 +213,6 @@
         "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
         "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
         "tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
-        "tests/src/**/systemui/statusbar/notification/PropertyAnimatorTest.java",
-        "tests/src/**/systemui/statusbar/notification/collection/NotifCollectionTest.java",
         "tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
         "tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
         "tests/src/**/systemui/statusbar/notification/collection/ShadeListBuilderTest.java",
@@ -233,9 +228,7 @@
         "tests/src/**/systemui/statusbar/notification/row/NotificationConversationInfoTest.java",
         "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerTest.java",
         "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt",
-        "tests/src/**/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt",
         "tests/src/**/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt",
-        "tests/src/**/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java",
         "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java",
         "tests/src/**/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt",
         "tests/src/**/systemui/statusbar/phone/AutoTileManagerTest.java",
@@ -250,7 +243,6 @@
         "tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt",
         "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt",
         "tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
         "tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt",
         "tests/src/**/systemui/statusbar/policy/CallbackControllerTest.java",
         "tests/src/**/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java",
@@ -263,11 +255,9 @@
         "tests/src/**/systemui/theme/ThemeOverlayApplierTest.java",
         "tests/src/**/systemui/touch/TouchInsetManagerTest.java",
         "tests/src/**/systemui/util/LifecycleFragmentTest.java",
-        "tests/src/**/systemui/util/TestableAlertDialogTest.kt",
         "tests/src/**/systemui/util/kotlin/PairwiseFlowTest",
         "tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
         "tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
-        "tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
         "tests/src/**/systemui/volume/VolumeDialogImplTest.java",
         "tests/src/**/systemui/wallet/controller/QuickAccessWalletControllerTest.java",
         "tests/src/**/systemui/wallet/ui/WalletScreenControllerTest.java",
@@ -288,9 +278,6 @@
         "tests/src/**/systemui/qs/QSImplTest.java",
         "tests/src/**/systemui/qs/panels/ui/compose/DragAndDropTest.kt",
         "tests/src/**/systemui/qs/panels/ui/compose/ResizingTest.kt",
-        "tests/src/**/systemui/screenshot/ActionExecutorTest.kt",
-        "tests/src/**/systemui/screenshot/ScreenshotDetectionControllerTest.kt",
-        "tests/src/**/systemui/screenshot/TakeScreenshotServiceTest.kt",
         "tests/src/**/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java",
         "tests/src/**/systemui/accessibility/floatingmenu/PositionTest.java",
         "tests/src/**/systemui/animation/TransitionAnimatorTest.kt",
@@ -303,10 +290,45 @@
         "tests/src/**/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt",
         "tests/src/**/systemui/statusbar/policy/RotationLockControllerImplTest.java",
         "tests/src/**/systemui/statusbar/phone/ScrimControllerTest.java",
-        "tests/src/**/systemui/stylus/StylusUsiPowerStartableTest.kt",
         "tests/src/**/systemui/toast/ToastUITest.java",
         "tests/src/**/systemui/statusbar/policy/FlashlightControllerImplTest.kt",
         "tests/src/**/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt",
+        "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
+    ],
+}
+
+// Files which use ExtendedMockito on the device.
+filegroup {
+    name: "SystemUI-tests-broken-robofiles-mockito-extended",
+    srcs: [
+        "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
+        "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
+        "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt",
+        "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
+        "tests/src/**/systemui/stylus/StylusManagerTest.kt",
+        "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
+        "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
+        "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
+        "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
+        "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
+        "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
+        "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
+        "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
+        "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
+        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
+        "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
+        "tests/src/**/systemui/wmshell/BubblesTest.java",
+        "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
+        "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
+        "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
+        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
+        "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
+        "tests/src/**/systemui/ScreenDecorationsTest.java",
+        "tests/src/**/keyguard/CarrierTextManagerTest.java",
+        "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
     ],
 }
 
@@ -314,29 +336,23 @@
 filegroup {
     name: "SystemUI-tests-broken-robofiles-compile",
     srcs: [
-        "tests/src/**/keyguard/KeyguardUpdateMonitorTest.java",
         "tests/src/**/systemui/statusbar/notification/icon/IconManagerTest.kt",
         "tests/src/**/systemui/statusbar/KeyguardIndicationControllerTest.java",
         "tests/src/**/systemui/doze/DozeScreenStateTest.java",
-        "tests/src/**/keyguard/CarrierTextManagerTest.java",
         "tests/src/**/systemui/notetask/NoteTaskInitializerTest.kt",
         "tests/src/**/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt",
         "tests/src/**/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt",
         "tests/src/**/systemui/controls/management/ControlsFavoritingActivityTest.kt",
         "tests/src/**/systemui/controls/management/ControlsProviderSelectorActivityTest.kt",
         "tests/src/**/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt",
         "tests/src/**/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt",
         "tests/src/**/systemui/qs/tileimpl/QSTileViewImplTest.kt",
-        "tests/src/**/systemui/statusbar/policy/BatteryStateNotifierTest.kt",
         "tests/src/**/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt",
         "tests/src/**/keyguard/ClockEventControllerTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothAutoOnRepositoryTest.kt",
-        "tests/src/**/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogRepositoryTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt",
-        "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt",
         "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt",
         "tests/src/**/systemui/broadcast/UserBroadcastDispatcherTest.kt",
         "tests/src/**/systemui/charging/WiredChargingRippleControllerTest.kt",
@@ -351,7 +367,6 @@
         "tests/src/**/systemui/controls/ui/SelectionItemTest.kt",
         "tests/src/**/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt",
         "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
         "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt",
         "tests/src/**/systemui/media/controls/ui/animation/AnimationBindHandlerTest.kt",
         "tests/src/**/systemui/media/controls/ui/animation/ColorSchemeTransitionTest.kt",
@@ -417,40 +432,9 @@
         "tests/src/**/systemui/statusbar/policy/VariableDateViewControllerTest.kt",
         "tests/src/**/systemui/statusbar/policy/WalletControllerImplTest.kt",
         "tests/src/**/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt",
-        "tests/src/**/systemui/stylus/StylusUsiPowerUiTest.kt",
         "tests/src/**/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt",
-        "tests/src/**/systemui/ScreenDecorationsTest.java",
-        "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt",
-        "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
-        "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
-        "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
-        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingButtonViewModelTest.kt",
-        "tests/src/**/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt",
-        "tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
-        "tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
-        "tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
-        "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
-        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
-        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
-        "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
-        "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
-        "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
-        "tests/src/**/systemui/stylus/StylusManagerTest.kt",
-        "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
-        "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
         "tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
-        "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
-        "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
-        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
-        "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
-        "tests/src/**/systemui/wmshell/BubblesTest.java",
-        "tests/src/**/systemui/power/PowerUITest.java",
-        "tests/src/**/systemui/qs/QSSecurityFooterTest.java",
-        "tests/src/**/systemui/qs/tileimpl/QSTileImplTest.java",
         "tests/src/**/systemui/shared/plugins/PluginActionManagerTest.java",
-        "tests/src/**/systemui/statusbar/CommandQueueTest.java",
-        "tests/src/**/systemui/statusbar/connectivity/CallbackHandlerTest.java",
         "tests/src/**/systemui/statusbar/policy/SecurityControllerTest.java",
         "tests/src/**/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt",
     ],
@@ -497,6 +481,9 @@
     resource_dirs: [],
     static_libs: [
         "//frameworks/libs/systemui:compilelib",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl",
         "SystemUI-res",
         "WifiTrackerLib",
         "WindowManager-Shell",
@@ -770,6 +757,9 @@
     ],
     static_libs: [
         "//frameworks/libs/systemui:compilelib",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl",
         "SystemUI-tests-base",
         "androidx.test.uiautomator_uiautomator",
         "androidx.core_core-animation-testing",
@@ -910,6 +900,7 @@
         ":SystemUI-tests-robofiles",
     ],
     exclude_srcs: [
+        ":SystemUI-tests-broken-robofiles-mockito-extended",
         ":SystemUI-tests-broken-robofiles-compile",
         ":SystemUI-tests-broken-robofiles-run",
         ":SystemUI-tests-broken-robofiles-sysui-run",
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 380344a..e47704eb 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -153,5 +153,11 @@
     {
       "path": "cts/tests/tests/multiuser"
     }
+  ],
+
+  "sysui-e2e-presubmit": [
+    {
+      "name": "PlatformScenarioTests_SysUI_Presubmit"
+    }
   ]
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a4b8821..123f823 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1748,6 +1748,13 @@
 }
 
 flag {
+    name: "notification_shade_blur"
+    namespace: "systemui"
+    description: "Enables the new blur effect on the Notification Shade."
+    bug: "370555223"
+}
+
+flag {
   name: "ensure_enr_views_visibility"
   namespace: "systemui"
   description: "Ensures public and private visibilities"
@@ -1790,4 +1797,4 @@
     metadata {
       purpose: PURPOSE_BUGFIX
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index 18f40c9..eee0caf 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -24,18 +24,22 @@
 import android.content.ComponentName
 import android.graphics.Color
 import android.graphics.Matrix
+import android.graphics.PointF
 import android.graphics.Rect
 import android.graphics.RectF
 import android.os.Binder
 import android.os.Build
 import android.os.Handler
+import android.os.IBinder
 import android.os.Looper
 import android.os.RemoteException
+import android.util.ArrayMap
 import android.util.Log
 import android.view.IRemoteAnimationFinishedCallback
 import android.view.IRemoteAnimationRunner
 import android.view.RemoteAnimationAdapter
 import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
 import android.view.SyncRtSurfaceTransactionApplier
 import android.view.View
 import android.view.ViewGroup
@@ -45,8 +49,12 @@
 import android.view.WindowManager.TRANSIT_TO_BACK
 import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.view.animation.PathInterpolator
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
 import android.window.RemoteTransition
 import android.window.TransitionFilter
+import android.window.TransitionInfo
+import android.window.WindowAnimationState
 import androidx.annotation.AnyThread
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
@@ -55,11 +63,14 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.Flags.activityTransitionUseLargestWindow
 import com.android.systemui.Flags.translucentOccludingActivityFix
+import com.android.systemui.animation.TransitionAnimator.Companion.assertLongLivedReturnAnimations
+import com.android.systemui.animation.TransitionAnimator.Companion.assertReturnAnimations
+import com.android.systemui.animation.TransitionAnimator.Companion.longLivedReturnAnimationsEnabled
+import com.android.systemui.animation.TransitionAnimator.Companion.returnAnimationsEnabled
 import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState
-import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
-import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
 import com.android.wm.shell.shared.IShellTransitions
 import com.android.wm.shell.shared.ShellTransitions
+import com.android.wm.shell.shared.TransitionUtil
 import java.util.concurrent.Executor
 import kotlin.math.roundToInt
 
@@ -194,7 +205,13 @@
         private const val LONG_TRANSITION_TIMEOUT = 5_000L
 
         private fun defaultTransitionAnimator(mainExecutor: Executor): TransitionAnimator {
-            return TransitionAnimator(mainExecutor, TIMINGS, INTERPOLATORS)
+            return TransitionAnimator(
+                mainExecutor,
+                TIMINGS,
+                INTERPOLATORS,
+                SPRING_TIMINGS,
+                SPRING_INTERPOLATORS,
+            )
         }
 
         private fun defaultDialogToAppAnimator(mainExecutor: Executor): TransitionAnimator {
@@ -275,7 +292,7 @@
                     "ActivityTransitionAnimator.callback must be set before using this animator"
                 )
         val runner = createRunner(controller)
-        val runnerDelegate = runner.delegate!!
+        val runnerDelegate = runner.delegate
         val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
 
         // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
@@ -330,7 +347,11 @@
         // If we expect an animation, post a timeout to cancel it in case the remote animation is
         // never started.
         if (willAnimate) {
-            runnerDelegate.postTimeouts()
+            if (longLivedReturnAnimationsEnabled()) {
+                runner.postTimeouts()
+            } else {
+                runnerDelegate!!.postTimeouts()
+            }
 
             // Hide the keyguard using the launch animation instead of the default unlock animation.
             if (hideKeyguardWithAnimation) {
@@ -390,7 +411,7 @@
         launchController: Controller,
         transitionRegister: TransitionRegister?,
     ) {
-        if (!returnAnimationFrameworkLibrary()) return
+        if (!returnAnimationsEnabled()) return
 
         var cleanUpRunnable: Runnable? = null
         val returnRunner =
@@ -413,7 +434,8 @@
                     private fun cleanUp() {
                         cleanUpRunnable?.run()
                     }
-                }
+                },
+                initializeLazily = longLivedReturnAnimationsEnabled(),
             )
 
         // mTypeSet and mModes match back signals only, and not home. This is on purpose, because
@@ -435,7 +457,11 @@
                 "${launchController.transitionCookie}_returnTransition",
             )
 
-        transitionRegister?.register(filter, transition)
+        transitionRegister?.register(
+            filter,
+            transition,
+            includeTakeover = longLivedReturnAnimationsEnabled(),
+        )
         cleanUpRunnable = Runnable { transitionRegister?.unregister(transition) }
     }
 
@@ -451,7 +477,10 @@
 
     /** Create a new animation [Runner] controlled by [controller]. */
     @VisibleForTesting
-    fun createRunner(controller: Controller): Runner {
+    @JvmOverloads
+    fun createRunner(controller: Controller, initializeLazily: Boolean = false): Runner {
+        if (initializeLazily) assertLongLivedReturnAnimations()
+
         // Make sure we use the modified timings when animating a dialog into an app.
         val transitionAnimator =
             if (controller.isDialogLaunch) {
@@ -460,7 +489,13 @@
                 transitionAnimator
             }
 
-        return Runner(controller, callback!!, transitionAnimator, lifecycleListener)
+        return Runner(
+            controller,
+            callback!!,
+            transitionAnimator,
+            lifecycleListener,
+            initializeLazily,
+        )
     }
 
     interface PendingIntentStarter {
@@ -628,10 +663,7 @@
      * this registration.
      */
     fun register(controller: Controller) {
-        check(returnAnimationFrameworkLongLived()) {
-            "Long-lived registrations cannot be used when the returnAnimationFrameworkLongLived " +
-                "flag is disabled"
-        }
+        assertLongLivedReturnAnimations()
 
         if (transitionRegister == null) {
             throw IllegalStateException(
@@ -667,10 +699,10 @@
             }
         val launchRemoteTransition =
             RemoteTransition(
-                RemoteAnimationRunnerCompat.wrap(createRunner(controller)),
+                OriginTransition(createRunner(controller, initializeLazily = true)),
                 "${cookie}_launchTransition",
             )
-        transitionRegister.register(launchFilter, launchRemoteTransition)
+        transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true)
 
         val returnController =
             object : Controller by controller {
@@ -689,10 +721,10 @@
             }
         val returnRemoteTransition =
             RemoteTransition(
-                RemoteAnimationRunnerCompat.wrap(createRunner(returnController)),
+                OriginTransition(createRunner(returnController, initializeLazily = true)),
                 "${cookie}_returnTransition",
             )
-        transitionRegister.register(returnFilter, returnRemoteTransition)
+        transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true)
 
         longLivedTransitions[cookie] = Pair(launchRemoteTransition, returnRemoteTransition)
     }
@@ -738,14 +770,154 @@
         }
     }
 
+    /** [Runner] wrapper that supports animation takeovers. */
+    private inner class OriginTransition(private val runner: Runner) : IRemoteTransition {
+        private val delegate = RemoteAnimationRunnerCompat.wrap(runner)
+
+        init {
+            assertLongLivedReturnAnimations()
+        }
+
+        override fun startAnimation(
+            token: IBinder?,
+            info: TransitionInfo?,
+            t: SurfaceControl.Transaction?,
+            finishCallback: IRemoteTransitionFinishedCallback?,
+        ) {
+            delegate.startAnimation(token, info, t, finishCallback)
+        }
+
+        override fun mergeAnimation(
+            transition: IBinder?,
+            info: TransitionInfo?,
+            t: SurfaceControl.Transaction?,
+            mergeTarget: IBinder?,
+            finishCallback: IRemoteTransitionFinishedCallback?,
+        ) {
+            delegate.mergeAnimation(transition, info, t, mergeTarget, finishCallback)
+        }
+
+        override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {
+            delegate.onTransitionConsumed(transition, aborted)
+        }
+
+        override fun takeOverAnimation(
+            token: IBinder?,
+            info: TransitionInfo?,
+            t: SurfaceControl.Transaction?,
+            finishCallback: IRemoteTransitionFinishedCallback?,
+            states: Array<WindowAnimationState>,
+        ) {
+            if (info == null || t == null) {
+                Log.e(
+                    TAG,
+                    "Skipping the animation takeover because the required data is missing: " +
+                        "info=$info, transaction=$t",
+                )
+                return
+            }
+
+            // The following code converts the contents of the given TransitionInfo into
+            // RemoteAnimationTargets. This is necessary because we must currently support both the
+            // new (Shell, remote transitions) and old (remote animations) framework to maintain
+            // functionality for all users of the library.
+            val apps = ArrayList<RemoteAnimationTarget>()
+            val filteredStates = ArrayList<WindowAnimationState>()
+            val leashMap = ArrayMap<SurfaceControl, SurfaceControl>()
+            val leafTaskFilter = TransitionUtil.LeafTaskFilter()
+
+            // About layering: we divide up the "layer space" into 2 regions (each the size of the
+            // change count). This lets us categorize things into above and below while
+            // maintaining their relative ordering.
+            val belowLayers = info.changes.size
+            val aboveLayers = info.changes.size * 2
+            for (i in info.changes.indices) {
+                val change = info.changes[i]
+                if (change == null || change.taskInfo == null) {
+                    continue
+                }
+
+                val taskInfo = change.taskInfo
+
+                if (TransitionUtil.isWallpaper(change)) {
+                    val target =
+                        TransitionUtil.newTarget(
+                            change,
+                            belowLayers - i, // wallpapers go into the "below" layer space
+                            info,
+                            t,
+                            leashMap,
+                        )
+
+                    // Make all the wallpapers opaque.
+                    t.setAlpha(target.leash, 1f)
+                } else if (leafTaskFilter.test(change)) {
+                    // Start by putting everything into the "below" layer space.
+                    val target =
+                        TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap)
+                    apps.add(target)
+                    filteredStates.add(states[i])
+
+                    // Make all the apps opaque.
+                    t.setAlpha(target.leash, 1f)
+
+                    if (
+                        TransitionUtil.isClosingType(change.mode) &&
+                            taskInfo?.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME
+                    ) {
+                        // Raise closing task to "above" layer so it isn't covered.
+                        t.setLayer(target.leash, aboveLayers - i)
+                    }
+                } else if (TransitionInfo.isIndependent(change, info)) {
+                    // Root tasks
+                    if (TransitionUtil.isClosingType(change.mode)) {
+                        // Raise closing task to "above" layer so it isn't covered.
+                        t.setLayer(change.leash, aboveLayers - i)
+                    } else if (TransitionUtil.isOpeningType(change.mode)) {
+                        // Put into the "below" layer space.
+                        t.setLayer(change.leash, belowLayers - i)
+                    }
+                } else if (TransitionUtil.isDividerBar(change)) {
+                    val target =
+                        TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap)
+                    apps.add(target)
+                    filteredStates.add(states[i])
+                }
+            }
+
+            val wrappedCallback: IRemoteAnimationFinishedCallback =
+                object : IRemoteAnimationFinishedCallback.Stub() {
+                    override fun onAnimationFinished() {
+                        leashMap.clear()
+                        val finishTransaction = SurfaceControl.Transaction()
+                        finishCallback?.onTransitionFinished(null, finishTransaction)
+                        finishTransaction.close()
+                    }
+                }
+
+            runner.takeOverAnimation(
+                apps.toTypedArray(),
+                filteredStates.toTypedArray(),
+                t,
+                wrappedCallback,
+            )
+        }
+
+        override fun asBinder(): IBinder {
+            return delegate.asBinder()
+        }
+    }
+
     @VisibleForTesting
     inner class Runner(
-        controller: Controller,
-        callback: Callback,
+        private val controller: Controller,
+        private val callback: Callback,
         /** The animator to use to animate the window transition. */
-        transitionAnimator: TransitionAnimator,
+        private val transitionAnimator: TransitionAnimator,
         /** Listener for animation lifecycle events. */
-        listener: Listener? = null,
+        private val listener: Listener? = null,
+        /** Whether the internal [delegate] should be initialized lazily. */
+        private val initializeLazily: Boolean = false,
     ) : IRemoteAnimationRunner.Stub() {
         // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
         // etc.) are possible. So we need to make sure we drop any references that might
@@ -753,15 +925,14 @@
         @VisibleForTesting var delegate: AnimationDelegate?
 
         init {
-            delegate =
-                AnimationDelegate(
-                    mainExecutor,
-                    controller,
-                    callback,
-                    DelegatingAnimationCompletionListener(listener, this::dispose),
-                    transitionAnimator,
-                    disableWmTimeout,
-                )
+            delegate = null
+            if (!initializeLazily) {
+                // Ephemeral launches bundle the runner with the launch request (instead of being
+                // registered ahead of time for later use). This means that there could be a timeout
+                // between creation and invocation, so the delegate needs to exist from the
+                // beginning in order to handle such timeout.
+                createDelegate()
+            }
         }
 
         @BinderThread
@@ -772,6 +943,36 @@
             nonApps: Array<out RemoteAnimationTarget>?,
             finishedCallback: IRemoteAnimationFinishedCallback?,
         ) {
+            initAndRun(finishedCallback) { delegate ->
+                delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+            }
+        }
+
+        @VisibleForTesting
+        @BinderThread
+        fun takeOverAnimation(
+            apps: Array<RemoteAnimationTarget>?,
+            windowAnimationStates: Array<WindowAnimationState>,
+            startTransaction: SurfaceControl.Transaction,
+            finishedCallback: IRemoteAnimationFinishedCallback?,
+        ) {
+            assertLongLivedReturnAnimations()
+            initAndRun(finishedCallback) { delegate ->
+                delegate.takeOverAnimation(
+                    apps,
+                    windowAnimationStates,
+                    startTransaction,
+                    finishedCallback,
+                )
+            }
+        }
+
+        @BinderThread
+        private fun initAndRun(
+            finishedCallback: IRemoteAnimationFinishedCallback?,
+            performAnimation: (AnimationDelegate) -> Unit,
+        ) {
+            maybeSetUp()
             val delegate = delegate
             mainExecutor.execute {
                 if (delegate == null) {
@@ -780,7 +981,7 @@
                     // signal back that we're done with it.
                     finishedCallback?.onAnimationFinished()
                 } else {
-                    delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback)
+                    performAnimation(delegate)
                 }
             }
         }
@@ -794,6 +995,32 @@
             }
         }
 
+        @VisibleForTesting
+        @UiThread
+        fun postTimeouts() {
+            maybeSetUp()
+            delegate?.postTimeouts()
+        }
+
+        @AnyThread
+        private fun maybeSetUp() {
+            if (!initializeLazily || delegate != null) return
+            createDelegate()
+        }
+
+        @AnyThread
+        private fun createDelegate() {
+            delegate =
+                AnimationDelegate(
+                    mainExecutor,
+                    controller,
+                    callback,
+                    DelegatingAnimationCompletionListener(listener, this::dispose),
+                    transitionAnimator,
+                    disableWmTimeout,
+                )
+        }
+
         @AnyThread
         fun dispose() {
             // Drop references to animation controller once we're done with the animation
@@ -867,7 +1094,7 @@
         init {
             // We do this check here to cover all entry points, including Launcher which doesn't
             // call startIntentWithAnimation()
-            if (!controller.isLaunching) TransitionAnimator.checkReturnAnimationFrameworkFlag()
+            if (!controller.isLaunching) assertReturnAnimations()
         }
 
         @UiThread
@@ -893,19 +1120,73 @@
             nonApps: Array<out RemoteAnimationTarget>?,
             callback: IRemoteAnimationFinishedCallback?,
         ) {
+            val window = setUpAnimation(apps, callback) ?: return
+
+            if (controller.windowAnimatorState == null || !longLivedReturnAnimationsEnabled()) {
+                val navigationBar =
+                    nonApps?.firstOrNull {
+                        it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+                    }
+
+                startAnimation(window, navigationBar, iCallback = callback)
+            } else {
+                // If a [controller.windowAnimatorState] exists, treat this like a takeover.
+                takeOverAnimationInternal(
+                    window,
+                    startWindowStates = null,
+                    startTransaction = null,
+                    callback,
+                )
+            }
+        }
+
+        @UiThread
+        internal fun takeOverAnimation(
+            apps: Array<out RemoteAnimationTarget>?,
+            startWindowStates: Array<WindowAnimationState>,
+            startTransaction: SurfaceControl.Transaction,
+            callback: IRemoteAnimationFinishedCallback?,
+        ) {
+            val window = setUpAnimation(apps, callback) ?: return
+            takeOverAnimationInternal(window, startWindowStates, startTransaction, callback)
+        }
+
+        private fun takeOverAnimationInternal(
+            window: RemoteAnimationTarget,
+            startWindowStates: Array<WindowAnimationState>?,
+            startTransaction: SurfaceControl.Transaction?,
+            callback: IRemoteAnimationFinishedCallback?,
+        ) {
+            val useSpring =
+                !controller.isLaunching && startWindowStates != null && startTransaction != null
+            startAnimation(
+                window,
+                navigationBar = null,
+                useSpring,
+                startWindowStates,
+                startTransaction,
+                callback,
+            )
+        }
+
+        @UiThread
+        private fun setUpAnimation(
+            apps: Array<out RemoteAnimationTarget>?,
+            callback: IRemoteAnimationFinishedCallback?,
+        ): RemoteAnimationTarget? {
             removeTimeouts()
 
             // The animation was started too late and we already notified the controller that it
             // timed out.
             if (timedOut) {
                 callback?.invoke()
-                return
+                return null
             }
 
             // This should not happen, but let's make sure we don't start the animation if it was
             // cancelled before and we already notified the controller.
             if (cancelled) {
-                return
+                return null
             }
 
             val window = findTargetWindowIfPossible(apps)
@@ -921,15 +1202,10 @@
                 }
                 controller.onTransitionAnimationCancelled()
                 listener?.onTransitionAnimationCancelled()
-                return
+                return null
             }
 
-            val navigationBar =
-                nonApps?.firstOrNull {
-                    it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
-                }
-
-            startAnimation(window, navigationBar, callback)
+            return window
         }
 
         private fun findTargetWindowIfPossible(
@@ -950,7 +1226,7 @@
             for (it in apps) {
                 if (it.mode == targetMode) {
                     if (activityTransitionUseLargestWindow()) {
-                        if (returnAnimationFrameworkLibrary()) {
+                        if (returnAnimationsEnabled()) {
                             // If the controller contains a cookie, _only_ match if either the
                             // candidate contains the matching cookie, or a component is also
                             // defined and is a match.
@@ -995,8 +1271,11 @@
 
         private fun startAnimation(
             window: RemoteAnimationTarget,
-            navigationBar: RemoteAnimationTarget?,
-            iCallback: IRemoteAnimationFinishedCallback?,
+            navigationBar: RemoteAnimationTarget? = null,
+            useSpring: Boolean = false,
+            startingWindowStates: Array<WindowAnimationState>? = null,
+            startTransaction: SurfaceControl.Transaction? = null,
+            iCallback: IRemoteAnimationFinishedCallback? = null,
         ) {
             if (TransitionAnimator.DEBUG) {
                 Log.d(TAG, "Remote animation started")
@@ -1046,18 +1325,66 @@
             val controller =
                 object : Controller by delegate {
                     override fun createAnimatorState(): TransitionAnimator.State {
-                        if (isLaunching) return delegate.createAnimatorState()
-                        return delegate.windowAnimatorState?.toTransitionState()
-                            ?: getWindowRadius(isExpandingFullyAbove).let {
-                                TransitionAnimator.State(
-                                    top = windowBounds.top,
-                                    bottom = windowBounds.bottom,
-                                    left = windowBounds.left,
-                                    right = windowBounds.right,
-                                    topCornerRadius = it,
-                                    bottomCornerRadius = it,
-                                )
+                        if (isLaunching) {
+                            return delegate.createAnimatorState()
+                        } else if (!longLivedReturnAnimationsEnabled()) {
+                            return delegate.windowAnimatorState?.toTransitionState()
+                                ?: getWindowRadius(isExpandingFullyAbove).let {
+                                    TransitionAnimator.State(
+                                        top = windowBounds.top,
+                                        bottom = windowBounds.bottom,
+                                        left = windowBounds.left,
+                                        right = windowBounds.right,
+                                        topCornerRadius = it,
+                                        bottomCornerRadius = it,
+                                    )
+                                }
+                        }
+
+                        // The states are sorted matching the changes inside the transition info.
+                        // Using this info, the RemoteAnimationTargets are created, with their
+                        // prefixOrderIndex fields in reverse order to that of changes. To extract
+                        // the right state, we need to invert again.
+                        val windowState =
+                            if (startingWindowStates != null) {
+                                startingWindowStates[
+                                    startingWindowStates.size - window.prefixOrderIndex]
+                            } else {
+                                controller.windowAnimatorState
                             }
+
+                        // TODO(b/323863002): use the timestamp and velocity to update the initial
+                        //   position.
+                        val bounds = windowState?.bounds
+                        val left: Int = bounds?.left?.toInt() ?: windowBounds.left
+                        val top: Int = bounds?.top?.toInt() ?: windowBounds.top
+                        val right: Int = bounds?.right?.toInt() ?: windowBounds.right
+                        val bottom: Int = bounds?.bottom?.toInt() ?: windowBounds.bottom
+
+                        val width = windowBounds.right - windowBounds.left
+                        val height = windowBounds.bottom - windowBounds.top
+                        // Scale the window. We use the max of (widthRatio, heightRatio) so that
+                        // there is no blank space on any side.
+                        val widthRatio = (right - left).toFloat() / width
+                        val heightRatio = (bottom - top).toFloat() / height
+                        val startScale = maxOf(widthRatio, heightRatio)
+
+                        val maybeRadius = windowState?.topLeftRadius
+                        val windowRadius =
+                            if (maybeRadius != null) {
+                                maybeRadius * startScale
+                            } else {
+                                getWindowRadius(isExpandingFullyAbove)
+                            }
+
+                        return TransitionAnimator.State(
+                            top = top,
+                            bottom = bottom,
+                            left = left,
+                            right = right,
+                            topCornerRadius = windowRadius,
+                            bottomCornerRadius = windowRadius,
+                        )
                     }
 
                     override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -1071,6 +1398,19 @@
                                     "[controller=$delegate]",
                             )
                         }
+
+                        if (startTransaction != null) {
+                            // Calling applyStateToWindow() here avoids skipping a frame when taking
+                            // over an animation.
+                            applyStateToWindow(
+                                window,
+                                createAnimatorState(),
+                                linearProgress = 0f,
+                                useSpring,
+                                startTransaction,
+                            )
+                        }
+
                         delegate.onTransitionAnimationStart(isExpandingFullyAbove)
                     }
 
@@ -1094,14 +1434,29 @@
                         progress: Float,
                         linearProgress: Float,
                     ) {
-                        applyStateToWindow(window, state, linearProgress)
+                        applyStateToWindow(window, state, linearProgress, useSpring)
                         navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
 
                         listener?.onTransitionAnimationProgress(linearProgress)
                         delegate.onTransitionAnimationProgress(state, progress, linearProgress)
                     }
                 }
-
+            val windowState =
+                if (startingWindowStates != null) {
+                    startingWindowStates[startingWindowStates.size - window.prefixOrderIndex]
+                } else {
+                    controller.windowAnimatorState
+                }
+            val velocityPxPerS =
+                if (longLivedReturnAnimationsEnabled() && windowState?.velocityPxPerMs != null) {
+                    val xVelocityPxPerS = windowState.velocityPxPerMs.x * 1000
+                    val yVelocityPxPerS = windowState.velocityPxPerMs.y * 1000
+                    PointF(xVelocityPxPerS, yVelocityPxPerS)
+                } else if (useSpring) {
+                    PointF(0f, 0f)
+                } else {
+                    null
+                }
             animation =
                 transitionAnimator.startAnimation(
                     controller,
@@ -1109,6 +1464,7 @@
                     windowBackgroundColor,
                     fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
                     drawHole = !controller.isBelowAnimatingWindow,
+                    startVelocity = velocityPxPerS,
                 )
         }
 
@@ -1128,6 +1484,8 @@
             window: RemoteAnimationTarget,
             state: TransitionAnimator.State,
             linearProgress: Float,
+            useSpring: Boolean,
+            transaction: SurfaceControl.Transaction? = null,
         ) {
             if (transactionApplierView.viewRootImpl == null || !window.leash.isValid) {
                 // Don't apply any transaction if the view root we synchronize with was detached or
@@ -1171,25 +1529,47 @@
                 windowCropF.bottom.roundToInt(),
             )
 
-            val windowAnimationDelay =
+            val interpolators: TransitionAnimator.Interpolators
+            val windowProgress: Float
+
+            if (useSpring) {
+                val windowAnimationDelay: Float
+                val windowAnimationDuration: Float
                 if (controller.isLaunching) {
-                    TIMINGS.contentAfterFadeInDelay
+                    windowAnimationDelay = SPRING_TIMINGS.contentAfterFadeInDelay
+                    windowAnimationDuration = SPRING_TIMINGS.contentAfterFadeInDuration
                 } else {
-                    TIMINGS.contentBeforeFadeOutDelay
+                    windowAnimationDelay = SPRING_TIMINGS.contentBeforeFadeOutDelay
+                    windowAnimationDuration = SPRING_TIMINGS.contentBeforeFadeOutDuration
                 }
-            val windowAnimationDuration =
+
+                interpolators = SPRING_INTERPOLATORS
+                windowProgress =
+                    TransitionAnimator.getProgress(
+                        linearProgress,
+                        windowAnimationDelay,
+                        windowAnimationDuration,
+                    )
+            } else {
+                val windowAnimationDelay: Long
+                val windowAnimationDuration: Long
                 if (controller.isLaunching) {
-                    TIMINGS.contentAfterFadeInDuration
+                    windowAnimationDelay = TIMINGS.contentAfterFadeInDelay
+                    windowAnimationDuration = TIMINGS.contentAfterFadeInDuration
                 } else {
-                    TIMINGS.contentBeforeFadeOutDuration
+                    windowAnimationDelay = TIMINGS.contentBeforeFadeOutDelay
+                    windowAnimationDuration = TIMINGS.contentBeforeFadeOutDuration
                 }
-            val windowProgress =
-                TransitionAnimator.getProgress(
-                    TIMINGS,
-                    linearProgress,
-                    windowAnimationDelay,
-                    windowAnimationDuration,
-                )
+
+                interpolators = INTERPOLATORS
+                windowProgress =
+                    TransitionAnimator.getProgress(
+                        TIMINGS,
+                        linearProgress,
+                        windowAnimationDelay,
+                        windowAnimationDuration,
+                    )
+            }
 
             // The alpha of the opening window. If it opens above the expandable, then it should
             // fade in progressively. Otherwise, it should be fully opaque and will be progressively
@@ -1197,12 +1577,12 @@
             val alpha =
                 if (controller.isBelowAnimatingWindow) {
                     if (controller.isLaunching) {
-                        INTERPOLATORS.contentAfterFadeInInterpolator.getInterpolation(
+                        interpolators.contentAfterFadeInInterpolator.getInterpolation(
                             windowProgress
                         )
                     } else {
                         1 -
-                            INTERPOLATORS.contentBeforeFadeOutInterpolator.getInterpolation(
+                            interpolators.contentBeforeFadeOutInterpolator.getInterpolation(
                                 windowProgress
                             )
                     }
@@ -1216,6 +1596,7 @@
             // especially important for lock screen animations, where the window is not clipped by
             // the shade.
             val cornerRadius = maxOf(state.topCornerRadius, state.bottomCornerRadius) / scale
+
             val params =
                 SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
                     .withAlpha(alpha)
@@ -1223,11 +1604,15 @@
                     .withWindowCrop(windowCrop)
                     .withCornerRadius(cornerRadius)
                     .withVisibility(true)
-                    .build()
+            if (transaction != null) params.withMergeTransaction(transaction)
 
-            transactionApplier.scheduleApply(params)
+            transactionApplier.scheduleApply(params.build())
         }
 
+        // TODO(b/377643129): remote transitions have no way of identifying the navbar when
+        //  converting to RemoteAnimationTargets (and in my testing it was never included in the
+        //  transition at all). So this method is not used anymore. Remove or adapt once we fully
+        //  convert to remote transitions.
         private fun applyStateToNavigationBar(
             navigationBar: RemoteAnimationTarget,
             state: TransitionAnimator.State,
@@ -1362,9 +1747,17 @@
         }
 
         /** Register [remoteTransition] with WM Shell using the given [filter]. */
-        internal fun register(filter: TransitionFilter, remoteTransition: RemoteTransition) {
+        internal fun register(
+            filter: TransitionFilter,
+            remoteTransition: RemoteTransition,
+            includeTakeover: Boolean,
+        ) {
             shellTransitions?.registerRemote(filter, remoteTransition)
             iShellTransitions?.registerRemote(filter, remoteTransition)
+            if (includeTakeover) {
+                shellTransitions?.registerRemoteForTakeover(filter, remoteTransition)
+                iShellTransitions?.registerRemoteForTakeover(filter, remoteTransition)
+            }
         }
 
         /** Unregister [remoteTransition] from WM Shell. */
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index fdb4871..de4bdbc 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -38,6 +38,7 @@
 import com.android.internal.dynamicanimation.animation.SpringAnimation
 import com.android.internal.dynamicanimation.animation.SpringForce
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
+import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
 import java.util.concurrent.Executor
 import kotlin.math.abs
 import kotlin.math.max
@@ -113,13 +114,26 @@
             )
         }
 
-        internal fun checkReturnAnimationFrameworkFlag() {
-            check(returnAnimationFrameworkLibrary()) {
-                "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is " +
-                    "disabled"
+        internal fun assertReturnAnimations() {
+            check(returnAnimationsEnabled()) {
+                "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag " +
+                    "is disabled"
             }
         }
 
+        internal fun returnAnimationsEnabled() = returnAnimationFrameworkLibrary()
+
+        internal fun assertLongLivedReturnAnimations() {
+            check(longLivedReturnAnimationsEnabled()) {
+                "Long-lived registrations cannot be used when the " +
+                    "returnAnimationFrameworkLibrary or the " +
+                    "returnAnimationFrameworkLongLived flag are disabled"
+            }
+        }
+
+        internal fun longLivedReturnAnimationsEnabled() =
+            returnAnimationFrameworkLibrary() && returnAnimationFrameworkLongLived()
+
         internal fun WindowAnimationState.toTransitionState() =
             State().also {
                 bounds?.let { b ->
@@ -467,7 +481,8 @@
         drawHole: Boolean = false,
         startVelocity: PointF? = null,
     ): Animation {
-        if (!controller.isLaunching || startVelocity != null) checkReturnAnimationFrameworkFlag()
+        if (!controller.isLaunching) assertReturnAnimations()
+        if (startVelocity != null) assertLongLivedReturnAnimations()
 
         // We add an extra layer with the same color as the dialog/app splash screen background
         // color, which is usually the same color of the app background. We first fade in this layer
diff --git a/packages/SystemUI/common/Android.bp b/packages/SystemUI/common/Android.bp
index 91dc3e3..9f15983 100644
--- a/packages/SystemUI/common/Android.bp
+++ b/packages/SystemUI/common/Android.bp
@@ -30,5 +30,9 @@
         "src/**/*.kt",
     ],
 
+    static_libs: ["SystemUI-shared-utils"],
+
+    libs: ["//frameworks/libs/systemui:tracinglib-platform"],
+
     kotlincflags: ["-Xjvm-default=all"],
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt b/packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
rename to packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
diff --git a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt b/packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
rename to packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
index d31d7aa..71ec63c 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
@@ -63,6 +63,9 @@
     return if (isDarkTheme) {
         dynamicDarkColorScheme(context)
             .copy(
+                inverseSurface = color(context, R.color.system_inverse_surface_dark),
+                inverseOnSurface = color(context, R.color.system_inverse_on_surface_dark),
+                inversePrimary = color(context, R.color.system_inverse_primary_dark),
                 error = color(context, R.color.system_error_dark),
                 onError = color(context, R.color.system_on_error_dark),
                 errorContainer = color(context, R.color.system_error_container_dark),
@@ -71,6 +74,9 @@
     } else {
         dynamicLightColorScheme(context)
             .copy(
+                inverseSurface = color(context, R.color.system_inverse_surface_light),
+                inverseOnSurface = color(context, R.color.system_inverse_on_surface_light),
+                inversePrimary = color(context, R.color.system_inverse_primary_light),
                 error = color(context, R.color.system_error_light),
                 onError = color(context, R.color.system_on_error_light),
                 errorContainer = color(context, R.color.system_error_container_light),
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
index de021a0..737853b 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt
@@ -89,7 +89,7 @@
             addValue(
                 "inversePrimary",
                 colorScheme.inversePrimary,
-                R.attr.materialColorPrimaryInverse,
+                R.attr.materialColorInversePrimary,
             )
             addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary)
             addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary)
@@ -131,12 +131,12 @@
             addValue(
                 "inverseSurface",
                 colorScheme.inverseSurface,
-                R.attr.materialColorSurfaceInverse,
+                R.attr.materialColorInverseSurface,
             )
             addValue(
                 "inverseOnSurface",
                 colorScheme.inverseOnSurface,
-                R.attr.materialColorOnSurfaceInverse,
+                R.attr.materialColorInverseOnSurface,
             )
             addValue("error", colorScheme.error, R.attr.materialColorError)
             addValue("onError", colorScheme.onError, R.attr.materialColorOnError)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 9392b1a..778d7e7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -66,13 +66,14 @@
                             interactionHandler = interactionHandler,
                             dialogFactory = dialogFactory,
                             widgetSection = widgetSection,
-                            modifier = Modifier.element(Communal.Elements.Grid)
+                            modifier = Modifier.element(Communal.Elements.Grid),
+                            sceneScope = this@Content,
                         )
                     }
                     with(lockSection) {
                         LockIcon(
                             overrideColor = MaterialTheme.colorScheme.onPrimaryContainer,
-                            modifier = Modifier.element(Communal.Elements.LockIcon)
+                            modifier = Modifier.element(Communal.Elements.LockIcon),
                         )
                     }
                     with(bottomAreaSection) {
@@ -80,17 +81,13 @@
                             Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth()
                         )
                     }
-                }
+                },
             ) { measurables, constraints ->
                 val communalGridMeasurable = measurables[0]
                 val lockIconMeasurable = measurables[1]
                 val bottomAreaMeasurable = measurables[2]
 
-                val noMinConstraints =
-                    constraints.copy(
-                        minWidth = 0,
-                        minHeight = 0,
-                    )
+                val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0)
 
                 val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
                 val lockIconBounds =
@@ -109,14 +106,8 @@
                     )
 
                 layout(constraints.maxWidth, constraints.maxHeight) {
-                    communalGridPlaceable.place(
-                        x = 0,
-                        y = 0,
-                    )
-                    lockIconPlaceable.place(
-                        x = lockIconBounds.left,
-                        y = lockIconBounds.top,
-                    )
+                    communalGridPlaceable.place(x = 0, y = 0)
+                    lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top)
                     bottomAreaPlaceable.place(
                         x = 0,
                         y = constraints.maxHeight - bottomAreaPlaceable.height,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 5e1ac1f..5b1203f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -163,6 +163,7 @@
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.window.layout.WindowMetricsCalculator
 import com.android.compose.animation.Easings.Emphasized
+import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
 import com.android.internal.R.dimen.system_app_widget_background_radius
@@ -186,7 +187,9 @@
 import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.statusbar.phone.SystemUIDialogFactory
 import kotlin.math.max
 import kotlin.math.min
@@ -205,6 +208,7 @@
     widgetConfigurator: WidgetConfigurator? = null,
     onOpenWidgetPicker: (() -> Unit)? = null,
     onEditDone: (() -> Unit)? = null,
+    sceneScope: SceneScope? = null,
 ) {
     val communalContent by
         viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList())
@@ -414,6 +418,7 @@
                             widgetConfigurator = widgetConfigurator,
                             interactionHandler = interactionHandler,
                             widgetSection = widgetSection,
+                            sceneScope = sceneScope,
                         )
                     }
                 }
@@ -735,6 +740,7 @@
     widgetConfigurator: WidgetConfigurator?,
     interactionHandler: RemoteViews.InteractionHandler?,
     widgetSection: CommunalAppWidgetSection,
+    sceneScope: SceneScope?,
 ) {
     var gridModifier =
         Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
@@ -807,7 +813,6 @@
                 ) {
                     ResizeableItemFrameViewModel()
                 }
-
             if (viewModel.isEditMode && dragDropState != null) {
                 val isItemDragging = dragDropState.draggingItemKey == item.key
                 val outlineAlpha by
@@ -872,6 +877,7 @@
                     interactionHandler = interactionHandler,
                     widgetSection = widgetSection,
                     resizeableItemFrameViewModel = resizeableItemFrameViewModel,
+                    sceneScope = sceneScope,
                 )
             }
         }
@@ -1096,6 +1102,7 @@
     interactionHandler: RemoteViews.InteractionHandler?,
     widgetSection: CommunalAppWidgetSection,
     resizeableItemFrameViewModel: ResizeableItemFrameViewModel,
+    sceneScope: SceneScope? = null,
 ) {
     when (model) {
         is CommunalContentModel.WidgetContent.Widget ->
@@ -1119,7 +1126,7 @@
         is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier)
         is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier)
         is CommunalContentModel.Tutorial -> TutorialContent(modifier)
-        is CommunalContentModel.Umo -> Umo(viewModel, modifier)
+        is CommunalContentModel.Umo -> Umo(viewModel, sceneScope, modifier)
     }
 }
 
@@ -1530,7 +1537,25 @@
 }
 
 @Composable
-private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) {
+private fun Umo(
+    viewModel: BaseCommunalViewModel,
+    sceneScope: SceneScope?,
+    modifier: Modifier = Modifier,
+) {
+    if (SceneContainerFlag.isEnabled && sceneScope != null) {
+        sceneScope.MediaCarousel(
+            modifier = modifier.fillMaxSize(),
+            isVisible = true,
+            mediaHost = viewModel.mediaHost,
+            carouselController = viewModel.mediaCarouselController,
+        )
+    } else {
+        UmoLegacy(viewModel, modifier)
+    }
+}
+
+@Composable
+private fun UmoLegacy(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) {
     AndroidView(
         modifier =
             modifier.pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
index 6e30575..16002bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt
@@ -59,7 +59,14 @@
     private val onAddWidget: (componentName: ComponentName, user: UserHandle, rank: Int) -> Unit,
     private val onDeleteWidget: (id: Int, componentName: ComponentName, rank: Int) -> Unit,
     private val onReorderWidgets: (widgetIdToRankMap: Map<Int, Int>) -> Unit,
-    private val onResizeWidget: (id: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) -> Unit,
+    private val onResizeWidget:
+        (
+            id: Int,
+            spanY: Int,
+            widgetIdToRankMap: Map<Int, Int>,
+            componentName: ComponentName,
+            rank: Int,
+        ) -> Unit,
 ) {
     var list = communalContent.toMutableStateList()
         private set
@@ -105,7 +112,9 @@
             } else {
                 emptyMap()
             }
-        onResizeWidget(item.appWidgetId, newSpan, widgetIdToRankMap)
+        val componentName = item.componentName
+        val rank = item.rank
+        onResizeWidget(item.appWidgetId, newSpan, widgetIdToRankMap, componentName, rank)
     }
 
     /**
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 20c8c6a3..2d32fd7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -36,6 +36,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Icon
 import androidx.compose.material3.LocalContentColor
@@ -84,6 +85,7 @@
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.qs.ui.composable.QuickSettingsTheme
+import com.android.systemui.qs.ui.compose.borderOnFocus
 import com.android.systemui.res.R
 import kotlinx.coroutines.launch
 
@@ -264,7 +266,11 @@
         color = colorAttr(model.backgroundColor),
         shape = CircleShape,
         onClick = model.onClick,
-        modifier = modifier,
+        modifier =
+            modifier.borderOnFocus(
+                color = MaterialTheme.colorScheme.secondary,
+                CornerSize(percent = 50),
+            ),
     ) {
         val tint = model.iconTint?.let { Color(it) } ?: Color.Unspecified
         Icon(model.icon, tint = tint, modifier = Modifier.size(20.dp))
@@ -291,7 +297,11 @@
         shape = CircleShape,
         onClick = onClick,
         interactionSource = interactionSource,
-        modifier = modifier,
+        modifier =
+            modifier.borderOnFocus(
+                color = MaterialTheme.colorScheme.secondary,
+                CornerSize(percent = 50),
+            ),
     ) {
         Box(Modifier.size(40.dp)) {
             Box(
@@ -342,7 +352,10 @@
         color = colorAttr(R.attr.underSurface),
         contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
         borderStroke = BorderStroke(1.dp, colorAttr(R.attr.shadeInactive)),
-        modifier = modifier.padding(horizontal = 4.dp),
+        modifier =
+            modifier
+                .padding(horizontal = 4.dp)
+                .borderOnFocus(color = MaterialTheme.colorScheme.secondary, CornerSize(50)),
         onClick = onClick,
     ) {
         Row(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 2cde678..9de7a5d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -15,7 +15,10 @@
 import com.android.systemui.scene.ui.composable.transitions.bouncerToLockscreenPreview
 import com.android.systemui.scene.ui.composable.transitions.communalToBouncerTransition
 import com.android.systemui.scene.ui.composable.transitions.communalToShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToBouncerTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToCommunalTransition
 import com.android.systemui.scene.ui.composable.transitions.dreamToGoneTransition
+import com.android.systemui.scene.ui.composable.transitions.dreamToShadeTransition
 import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
 import com.android.systemui.scene.ui.composable.transitions.goneToShadeTransition
 import com.android.systemui.scene.ui.composable.transitions.goneToSplitShadeTransition
@@ -55,7 +58,10 @@
     // Scene transitions
 
     from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
+    from(Scenes.Dream, to = Scenes.Bouncer) { dreamToBouncerTransition() }
+    from(Scenes.Dream, to = Scenes.Communal) { dreamToCommunalTransition() }
     from(Scenes.Dream, to = Scenes.Gone) { dreamToGoneTransition() }
+    from(Scenes.Dream, to = Scenes.Shade) { dreamToShadeTransition() }
     from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
     from(Scenes.Gone, to = Scenes.Shade, key = ToSplitShade) { goneToSplitShadeTransition() }
     from(Scenes.Gone, to = Scenes.Shade, key = SlightlyFasterShadeCollapse) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt
index e4ccc2c..8cb89f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToBouncerTransition.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package com.android.systemui.scene.ui.composable.transitions
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import com.android.compose.animation.scene.TransitionBuilder
+
+fun TransitionBuilder.dreamToBouncerTransition() {
+    toBouncerTransition()
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt
new file mode 100644
index 0000000..93c10b6
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.scene.ui.composable.transitions
+
+import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.communal.ui.compose.AllElements
+import com.android.systemui.communal.ui.compose.Communal
+
+fun TransitionBuilder.dreamToCommunalTransition() {
+    spec = tween(durationMillis = 1000)
+
+    // Translate communal hub grid from the end direction.
+    translate(Communal.Elements.Grid, Edge.End)
+
+    // Fade all communal hub elements.
+    timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt
similarity index 70%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt
index e4ccc2c..e35aaae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToShadeTransition.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package com.android.systemui.scene.ui.composable.transitions
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import com.android.compose.animation.scene.TransitionBuilder
+
+fun TransitionBuilder.dreamToShadeTransition(durationScale: Double = 1.0) {
+    toShadeTransition(durationScale = durationScale)
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index 71fa6c9..ce7a85b1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -19,11 +19,8 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
 import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.ui.composable.QuickSettings
@@ -31,24 +28,17 @@
 import com.android.systemui.shade.ui.composable.ShadeHeader
 import kotlin.time.Duration.Companion.milliseconds
 
-fun TransitionBuilder.goneToSplitShadeTransition(
-    durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.goneToSplitShadeTransition(durationScale: Double = 1.0) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
     swipeSpec =
         spring(
             stiffness = Spring.StiffnessMediumLow,
             visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
         )
-    distance =
-        object : UserActionDistance {
-            override fun UserActionDistanceScope.absoluteDistance(
-                fromSceneSize: IntSize,
-                orientation: Orientation,
-            ): Float {
-                return fromSceneSize.height.toFloat() * 2 / 3f
-            }
-        }
+    distance = UserActionDistance { fromContent, _, _ ->
+        val fromContentSize = checkNotNull(fromContent.targetSize())
+        fromContentSize.height.toFloat() * 2 / 3f
+    }
 
     fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
index 1486ea7..1f7a738 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt
@@ -19,35 +19,25 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.shade.ui.composable.Shade
 import com.android.systemui.shade.ui.composable.ShadeHeader
 import kotlin.time.Duration.Companion.milliseconds
 
-fun TransitionBuilder.lockscreenToSplitShadeTransition(
-    durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.lockscreenToSplitShadeTransition(durationScale: Double = 1.0) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
     swipeSpec =
         spring(
             stiffness = Spring.StiffnessMediumLow,
             visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
         )
-    distance =
-        object : UserActionDistance {
-            override fun UserActionDistanceScope.absoluteDistance(
-                fromSceneSize: IntSize,
-                orientation: Orientation,
-            ): Float {
-                return fromSceneSize.height.toFloat() * 2 / 3f
-            }
-        }
+    distance = UserActionDistance { fromContent, _, _ ->
+        val fromContentSize = checkNotNull(fromContent.targetSize())
+        fromContentSize.height.toFloat() * 2 / 3f
+    }
 
     fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 8cd357e..ba1972f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -1,46 +1,36 @@
 package com.android.systemui.scene.ui.composable.transitions
 
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ui.composable.ShadeHeader
 import kotlin.time.Duration.Companion.milliseconds
 
-fun TransitionBuilder.shadeToQuickSettingsTransition(
-    durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.shadeToQuickSettingsTransition(durationScale: Double = 1.0) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
-    distance =
-        object : UserActionDistance {
-            override fun UserActionDistanceScope.absoluteDistance(
-                fromSceneSize: IntSize,
-                orientation: Orientation,
-            ): Float {
-                val distance =
-                    Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y
-                        ?: return 0f
-                return fromSceneSize.height - distance
-            }
-        }
+    distance = UserActionDistance { fromContent, _, _ ->
+        val distance =
+            Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y
+                ?: return@UserActionDistance 0f
+        val fromContentSize = checkNotNull(fromContent.targetSize())
+        fromContentSize.height - distance
+    }
 
     translate(Notifications.Elements.NotificationScrim, Edge.Bottom)
     timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
 
     translate(
         ShadeHeader.Elements.CollapsedContentStart,
-        y = ShadeHeader.Dimensions.CollapsedHeight
+        y = ShadeHeader.Dimensions.CollapsedHeight,
     )
     translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight)
     translate(
         ShadeHeader.Elements.ExpandedContent,
-        y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight)
+        y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight),
     )
     translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight)
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
index de76f70..d35537a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt
@@ -28,8 +28,9 @@
 fun TransitionBuilder.toBouncerTransition() {
     spec = tween(durationMillis = 500)
 
-    distance = UserActionDistance { fromSceneSize, _ ->
-        fromSceneSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION
+    distance = UserActionDistance { fromContent, _, _ ->
+        val fromContentSize = checkNotNull(fromContent.targetSize())
+        fromContentSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION
     }
 
     translate(Bouncer.Elements.Content, y = 300.dp)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 55fa6ad..e78bc6a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -33,7 +33,10 @@
             stiffness = Spring.StiffnessMediumLow,
             visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
         )
-    distance = UserActionDistance { fromSceneSize, _ -> fromSceneSize.height.toFloat() * 2 / 3f }
+    distance = UserActionDistance { fromContent, _, _ ->
+        val fromContentSize = checkNotNull(fromContent.targetSize())
+        fromContentSize.height.toFloat() * 2 / 3f
+    }
 
     translate(OverlayShade.Elements.Panel, Edge.Top)
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index b677dff..bfae489 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -19,12 +19,9 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
-import com.android.compose.animation.scene.UserActionDistanceScope
 import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.ui.composable.QuickSettings
@@ -33,24 +30,16 @@
 import com.android.systemui.shade.ui.composable.ShadeHeader
 import kotlin.time.Duration.Companion.milliseconds
 
-fun TransitionBuilder.toShadeTransition(
-    durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.toShadeTransition(durationScale: Double = 1.0) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
     swipeSpec =
         spring(
             stiffness = Spring.StiffnessMediumLow,
             visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
         )
-    distance =
-        object : UserActionDistance {
-            override fun UserActionDistanceScope.absoluteDistance(
-                fromSceneSize: IntSize,
-                orientation: Orientation,
-            ): Float {
-                return Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f
-            }
-        }
+    distance = UserActionDistance { _, _, _ ->
+        Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f
+    }
 
     fractionRange(start = .58f) {
         fade(ShadeHeader.Elements.Clock)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
index 163f4b3..78e6056 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt
@@ -307,6 +307,6 @@
 
 private object DraggableBottomSheet {
     val DefaultTopPadding = 64.dp
-    val LargeScreenTopPadding = 72.dp
+    val LargeScreenTopPadding = 56.dp
     val MaxWidth = 640.dp
 }
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 c33d655..04c5271 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
@@ -530,16 +530,12 @@
 }
 
 internal class NestedScrollHandlerImpl(
-    private val layoutImpl: SceneTransitionLayoutImpl,
-    private val orientation: Orientation,
+    private val draggableHandler: DraggableHandlerImpl,
     internal var topOrLeftBehavior: NestedScrollBehavior,
     internal var bottomOrRightBehavior: NestedScrollBehavior,
     internal var isExternalOverscrollGesture: () -> Boolean,
     private val pointersInfoOwner: PointersInfoOwner,
 ) {
-    private val layoutState = layoutImpl.state
-    private val draggableHandler = layoutImpl.draggableHandler(orientation)
-
     val connection: PriorityNestedScrollConnection = nestedScrollConnection()
 
     private fun nestedScrollConnection(): PriorityNestedScrollConnection {
@@ -550,13 +546,15 @@
         var lastPointersDown: PointersInfo.PointersDown? = null
 
         fun shouldEnableSwipes(): Boolean {
-            return layoutImpl.contentForUserActions().shouldEnableSwipes(orientation)
+            return draggableHandler.layoutImpl
+                .contentForUserActions()
+                .shouldEnableSwipes(draggableHandler.orientation)
         }
 
         var isIntercepting = false
 
         return PriorityNestedScrollConnection(
-            orientation = orientation,
+            orientation = draggableHandler.orientation,
             canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ ->
                 val pointersDown: PointersInfo.PointersDown? =
                     when (val info = pointersInfoOwner.pointersInfo()) {
@@ -578,8 +576,9 @@
                         draggableHandler.shouldImmediatelyIntercept(pointersDown)
                 if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
 
+                val layoutImpl = draggableHandler.layoutImpl
                 val threshold = layoutImpl.transitionInterceptionThreshold
-                val hasSnappedToIdle = layoutState.snapToIdleIfClose(threshold)
+                val hasSnappedToIdle = layoutImpl.state.snapToIdleIfClose(threshold)
                 if (hasSnappedToIdle) {
                     // If the current swipe transition is closed to 0f or 1f, then we want to
                     // interrupt the transition (snapping it to Idle) and scroll the list.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index d976e8e..eb2a016 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -50,6 +50,8 @@
 import androidx.compose.ui.util.lerp
 import com.android.compose.animation.scene.content.Content
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.InterpolatedPropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformation
 import com.android.compose.animation.scene.transformation.SharedElementTransformation
 import com.android.compose.animation.scene.transformation.TransformationWithRange
@@ -348,8 +350,7 @@
             val placeInThisContent =
                 elementContentWhenIdle(
                     layoutImpl,
-                    currentState.currentScene,
-                    currentState.currentOverlays,
+                    currentState,
                     isInContent = { it in element.stateByContent },
                 ) == content.key
 
@@ -637,20 +638,11 @@
 
 internal inline fun elementContentWhenIdle(
     layoutImpl: SceneTransitionLayoutImpl,
-    idle: TransitionState.Idle,
+    currentState: TransitionState,
     isInContent: (ContentKey) -> Boolean,
 ): ContentKey {
-    val currentScene = idle.currentScene
-    val overlays = idle.currentOverlays
-    return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent)
-}
-
-private inline fun elementContentWhenIdle(
-    layoutImpl: SceneTransitionLayoutImpl,
-    currentScene: SceneKey,
-    overlays: Set<OverlayKey>,
-    isInContent: (ContentKey) -> Boolean,
-): ContentKey {
+    val currentScene = currentState.currentScene
+    val overlays = currentState.currentOverlays
     if (overlays.isEmpty()) {
         return currentScene
     }
@@ -1308,7 +1300,14 @@
                 checkNotNull(if (currentContent == toContent) toState else fromState)
             val idleValue = contentValue(overscrollState)
             val targetValue =
-                with(propertySpec.transformation) {
+                with(
+                    propertySpec.transformation.requireInterpolatedTransformation(
+                        element,
+                        transition,
+                    ) {
+                        "Custom transformations in overscroll specs should not be possible"
+                    }
+                ) {
                     layoutImpl.propertyTransformationScope.transform(
                         currentContent,
                         element.key,
@@ -1390,7 +1389,7 @@
     // fromContent or toContent during interruptions.
     val content = contentState.content
 
-    val transformation =
+    val transformationWithRange =
         transformation(transition.transformationSpec.transformations(element.key, content))
 
     val previewTransformation =
@@ -1403,7 +1402,14 @@
         val idleValue = contentValue(contentState)
         val isEntering = content == toContent
         val previewTargetValue =
-            with(previewTransformation.transformation) {
+            with(
+                previewTransformation.transformation.requireInterpolatedTransformation(
+                    element,
+                    transition,
+                ) {
+                    "Custom transformations in preview specs should not be possible"
+                }
+            ) {
                 layoutImpl.propertyTransformationScope.transform(
                     content,
                     element.key,
@@ -1413,8 +1419,15 @@
             }
 
         val targetValueOrNull =
-            transformation?.let { transformation ->
-                with(transformation.transformation) {
+            transformationWithRange?.let { transformation ->
+                with(
+                    transformation.transformation.requireInterpolatedTransformation(
+                        element,
+                        transition,
+                    ) {
+                        "Custom transformations are not allowed for properties with a preview"
+                    }
+                ) {
                     layoutImpl.propertyTransformationScope.transform(
                         content,
                         element.key,
@@ -1461,7 +1474,7 @@
             lerp(
                 lerp(previewTargetValue, targetValueOrNull ?: idleValue, previewRangeProgress),
                 idleValue,
-                transformation?.range?.progress(transition.progress) ?: transition.progress,
+                transformationWithRange?.range?.progress(transition.progress) ?: transition.progress,
             )
         } else {
             if (targetValueOrNull == null) {
@@ -1474,22 +1487,39 @@
                 lerp(
                     lerp(idleValue, previewTargetValue, previewRangeProgress),
                     targetValueOrNull,
-                    transformation.range?.progress(transition.progress) ?: transition.progress,
+                    transformationWithRange.range?.progress(transition.progress)
+                        ?: transition.progress,
                 )
             }
         }
     }
 
-    if (transformation == null) {
+    if (transformationWithRange == null) {
         // If there is no transformation explicitly associated to this element value, let's use
         // the value given by the system (like the current position and size given by the layout
         // pass).
         return currentValue()
     }
 
+    val transformation = transformationWithRange.transformation
+    when (transformation) {
+        is CustomPropertyTransformation ->
+            return with(transformation) {
+                layoutImpl.propertyTransformationScope.transform(
+                    content,
+                    element.key,
+                    transition,
+                    transition.coroutineScope,
+                )
+            }
+        is InterpolatedPropertyTransformation -> {
+            /* continue */
+        }
+    }
+
     val idleValue = contentValue(contentState)
     val targetValue =
-        with(transformation.transformation) {
+        with(transformation) {
             layoutImpl.propertyTransformationScope.transform(
                 content,
                 element.key,
@@ -1506,7 +1536,7 @@
 
     val progress = transition.progress
     // TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
-    val rangeProgress = transformation.range?.progress(progress) ?: progress
+    val rangeProgress = transformationWithRange.range?.progress(progress) ?: progress
 
     // Interpolate between the value at rest and the value before entering/after leaving.
     val isEntering =
@@ -1523,6 +1553,22 @@
     }
 }
 
+private inline fun <T> PropertyTransformation<T>.requireInterpolatedTransformation(
+    element: Element,
+    transition: TransitionState.Transition,
+    errorMessage: () -> String,
+): InterpolatedPropertyTransformation<T> {
+    return when (this) {
+        is InterpolatedPropertyTransformation -> this
+        is CustomPropertyTransformation -> {
+            val elem = element.key.debugName
+            val fromContent = transition.fromContent
+            val toContent = transition.toContent
+            error("${errorMessage()} (element=$elem fromContent=$fromContent toContent=$toContent)")
+        }
+    }
+}
+
 private inline fun <T> interpolateSharedElement(
     transition: TransitionState.Transition,
     contentValue: (Element.State) -> T,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index c790ff0..509a16c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -188,7 +188,9 @@
     return when (
         val elementState = movableElementState(element, layoutImpl.state.transitionStates)
     ) {
-        null -> false
+        null ->
+            movableElementContentWhenIdle(layoutImpl, element, layoutImpl.state.transitionState) ==
+                content
         is TransitionState.Idle ->
             movableElementContentWhenIdle(layoutImpl, element, elementState) == content
         is TransitionState.Transition -> {
@@ -217,7 +219,7 @@
 private fun movableElementContentWhenIdle(
     layoutImpl: SceneTransitionLayoutImpl,
     element: MovableElementKey,
-    elementState: TransitionState.Idle,
+    elementState: TransitionState,
 ): ContentKey {
     val contents = element.contentPicker.contents
     return elementContentWhenIdle(layoutImpl, elementState, isInContent = { contents.contains(it) })
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 fbd1cd5..955be60 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
@@ -16,7 +16,6 @@
 
 package com.android.compose.animation.scene
 
-import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
@@ -69,32 +68,28 @@
 }
 
 internal fun Modifier.nestedScrollToScene(
-    layoutImpl: SceneTransitionLayoutImpl,
-    orientation: Orientation,
+    draggableHandler: DraggableHandlerImpl,
     topOrLeftBehavior: NestedScrollBehavior,
     bottomOrRightBehavior: NestedScrollBehavior,
     isExternalOverscrollGesture: () -> Boolean,
 ) =
     this then
         NestedScrollToSceneElement(
-            layoutImpl = layoutImpl,
-            orientation = orientation,
+            draggableHandler = draggableHandler,
             topOrLeftBehavior = topOrLeftBehavior,
             bottomOrRightBehavior = bottomOrRightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
         )
 
 private data class NestedScrollToSceneElement(
-    private val layoutImpl: SceneTransitionLayoutImpl,
-    private val orientation: Orientation,
+    private val draggableHandler: DraggableHandlerImpl,
     private val topOrLeftBehavior: NestedScrollBehavior,
     private val bottomOrRightBehavior: NestedScrollBehavior,
     private val isExternalOverscrollGesture: () -> Boolean,
 ) : ModifierNodeElement<NestedScrollToSceneNode>() {
     override fun create() =
         NestedScrollToSceneNode(
-            layoutImpl = layoutImpl,
-            orientation = orientation,
+            draggableHandler = draggableHandler,
             topOrLeftBehavior = topOrLeftBehavior,
             bottomOrRightBehavior = bottomOrRightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -102,8 +97,7 @@
 
     override fun update(node: NestedScrollToSceneNode) {
         node.update(
-            layoutImpl = layoutImpl,
-            orientation = orientation,
+            draggableHandler = draggableHandler,
             topOrLeftBehavior = topOrLeftBehavior,
             bottomOrRightBehavior = bottomOrRightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -112,16 +106,14 @@
 
     override fun InspectorInfo.inspectableProperties() {
         name = "nestedScrollToScene"
-        properties["layoutImpl"] = layoutImpl
-        properties["orientation"] = orientation
+        properties["draggableHandler"] = draggableHandler
         properties["topOrLeftBehavior"] = topOrLeftBehavior
         properties["bottomOrRightBehavior"] = bottomOrRightBehavior
     }
 }
 
 private class NestedScrollToSceneNode(
-    private var layoutImpl: SceneTransitionLayoutImpl,
-    private var orientation: Orientation,
+    private var draggableHandler: DraggableHandlerImpl,
     private var topOrLeftBehavior: NestedScrollBehavior,
     private var bottomOrRightBehavior: NestedScrollBehavior,
     private var isExternalOverscrollGesture: () -> Boolean,
@@ -129,12 +121,8 @@
     private var scrollBehaviorOwner: ScrollBehaviorOwner? = null
 
     private fun findScrollBehaviorOwner(): ScrollBehaviorOwner? {
-        var behaviorOwner = scrollBehaviorOwner
-        if (behaviorOwner == null) {
-            behaviorOwner = findScrollBehaviorOwner(layoutImpl.draggableHandler(orientation))
-            scrollBehaviorOwner = behaviorOwner
-        }
-        return behaviorOwner
+        return scrollBehaviorOwner
+            ?: findScrollBehaviorOwner(draggableHandler).also { scrollBehaviorOwner = it }
     }
 
     private val updateScrollBehaviorsConnection =
@@ -177,14 +165,12 @@
     }
 
     fun update(
-        layoutImpl: SceneTransitionLayoutImpl,
-        orientation: Orientation,
+        draggableHandler: DraggableHandlerImpl,
         topOrLeftBehavior: NestedScrollBehavior,
         bottomOrRightBehavior: NestedScrollBehavior,
         isExternalOverscrollGesture: () -> Boolean,
     ) {
-        this.layoutImpl = layoutImpl
-        this.orientation = orientation
+        this.draggableHandler = draggableHandler
         this.topOrLeftBehavior = topOrLeftBehavior
         this.bottomOrRightBehavior = bottomOrRightBehavior
         this.isExternalOverscrollGesture = isExternalOverscrollGesture
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index dbf7d7b..d3ddb50 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -637,8 +637,8 @@
 
 fun interface UserActionDistance {
     /**
-     * Return the **absolute** distance of the user action given the size of the scene we are
-     * animating from and the [orientation].
+     * Return the **absolute** distance of the user action when going from [fromContent] to
+     * [toContent] in the given [orientation].
      *
      * Note: This function will be called for each drag event until it returns a value > 0f. This
      * for instance allows you to return 0f or a negative value until the first layout pass of a
@@ -646,7 +646,8 @@
      * transitioning to when computing this absolute distance.
      */
     fun UserActionDistanceScope.absoluteDistance(
-        fromSceneSize: IntSize,
+        fromContent: ContentKey,
+        toContent: ContentKey,
         orientation: Orientation,
     ): Float
 }
@@ -656,7 +657,8 @@
 /** The user action has a fixed [absoluteDistance]. */
 class FixedDistance(private val distance: Dp) : UserActionDistance {
     override fun UserActionDistanceScope.absoluteDistance(
-        fromSceneSize: IntSize,
+        fromContent: ContentKey,
+        toContent: ContentKey,
         orientation: Orientation,
     ): Float = distance.toPx()
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index e93cf8f7..b916b0b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -125,8 +125,8 @@
                 }
 
     // TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed.
-    private val horizontalDraggableHandler: DraggableHandlerImpl
-    private val verticalDraggableHandler: DraggableHandlerImpl
+    internal val horizontalDraggableHandler: DraggableHandlerImpl
+    internal val verticalDraggableHandler: DraggableHandlerImpl
 
     internal val elementStateScope = ElementStateScopeImpl(this)
     internal val propertyTransformationScope = PropertyTransformationScopeImpl(this)
@@ -163,12 +163,6 @@
         state.checkThread()
     }
 
-    internal fun draggableHandler(orientation: Orientation): DraggableHandlerImpl =
-        when (orientation) {
-            Orientation.Vertical -> verticalDraggableHandler
-            Orientation.Horizontal -> horizontalDraggableHandler
-        }
-
     internal fun scene(key: SceneKey): Scene {
         return scenes[key] ?: error("Scene $key is not configured")
     }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 72b29ee..3bf2ed5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -32,6 +32,7 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
 
 /**
@@ -266,11 +267,12 @@
         private set
 
     /**
-     * The flattened list of [SharedElementTransformation] within all the transitions in
+     * The flattened list of [SharedElementTransformation.Factory] within all the transitions in
      * [transitionStates].
      */
-    private val transformationsWithElevation: List<SharedElementTransformation> by derivedStateOf {
-        transformationsWithElevation(transitionStates)
+    private val transformationFactoriesWithElevation:
+        List<SharedElementTransformation.Factory> by derivedStateOf {
+        transformationFactoriesWithElevation(transitionStates)
     }
 
     override val currentScene: SceneKey
@@ -354,6 +356,12 @@
     override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
         checkThread()
 
+        // Prepare the transition before starting it. This is outside of the try/finally block on
+        // purpose because preparing a transition might throw an exception (e.g. if we find multiple
+        // specs matching this transition), in which case we want to throw that exception here
+        // before even starting the transition.
+        prepareTransitionBeforeStarting(transition)
+
         try {
             // Start the transition.
             startTransitionInternal(transition, chain)
@@ -365,7 +373,7 @@
         }
     }
 
-    private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
+    private fun prepareTransitionBeforeStarting(transition: TransitionState.Transition) {
         // Set the current scene and overlays on the transition.
         val currentState = transitionState
         transition.currentSceneWhenTransitionStarted = currentState.currentScene
@@ -393,7 +401,9 @@
         } else {
             transition.updateOverscrollSpecs(fromSpec = null, toSpec = null)
         }
+    }
 
+    private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
         when (val currentState = transitionStates.last()) {
             is TransitionState.Idle -> {
                 // Replace [Idle] by [transition].
@@ -466,9 +476,9 @@
             return
         }
 
-        // Make sure that this transition settles in case it was force finished, for instance by
-        // calling snapToScene().
-        transition.freezeAndAnimateToCurrentState()
+        // Make sure that this transition is cancelled in case it was force finished, for instance
+        // if snapToScene() is called.
+        transition.coroutineScope.cancel()
 
         val transitionStates = this.transitionStates
         if (!transitionStates.contains(transition)) {
@@ -550,8 +560,8 @@
         }
 
         val shouldSnap =
-            (isProgressCloseTo(0f) && transition.currentScene == transition.fromContent) ||
-                (isProgressCloseTo(1f) && transition.currentScene == transition.toContent)
+            (isProgressCloseTo(0f) && transition.isFromCurrentContent()) ||
+                (isProgressCloseTo(1f) && transition.isToCurrentContent())
         return if (shouldSnap) {
             finishAllTransitions()
             true
@@ -691,22 +701,23 @@
         animate()
     }
 
-    private fun transformationsWithElevation(
+    private fun transformationFactoriesWithElevation(
         transitionStates: List<TransitionState>
-    ): List<SharedElementTransformation> {
+    ): List<SharedElementTransformation.Factory> {
         return buildList {
             transitionStates.fastForEach { state ->
                 if (state !is TransitionState.Transition) {
                     return@fastForEach
                 }
 
-                state.transformationSpec.transformations.fastForEach { transformationWithRange ->
-                    val transformation = transformationWithRange.transformation
+                state.transformationSpec.transformationMatchers.fastForEach { transformationMatcher
+                    ->
+                    val factory = transformationMatcher.factory
                     if (
-                        transformation is SharedElementTransformation &&
-                            transformation.elevateInContent != null
+                        factory is SharedElementTransformation.Factory &&
+                            factory.elevateInContent != null
                     ) {
-                        add(transformation)
+                        add(factory)
                     }
                 }
             }
@@ -721,10 +732,10 @@
      * necessary, for performance.
      */
     internal fun isElevationPossible(content: ContentKey, element: ElementKey?): Boolean {
-        if (transformationsWithElevation.isEmpty()) return false
-        return transformationsWithElevation.fastAny { transformation ->
-            transformation.elevateInContent == content &&
-                (element == null || transformation.matcher.matches(element, content))
+        if (transformationFactoriesWithElevation.isEmpty()) return false
+        return transformationFactoriesWithElevation.fastAny { factory ->
+            factory.elevateInContent == content &&
+                (element == null || factory.matcher.matches(element, content))
         }
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index b083f79..8df3f2d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -26,18 +26,10 @@
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
 import com.android.compose.animation.scene.content.state.TransitionState
-import com.android.compose.animation.scene.transformation.AnchoredSize
-import com.android.compose.animation.scene.transformation.AnchoredTranslate
-import com.android.compose.animation.scene.transformation.DrawScale
-import com.android.compose.animation.scene.transformation.EdgeTranslate
-import com.android.compose.animation.scene.transformation.Fade
-import com.android.compose.animation.scene.transformation.OverscrollTranslate
 import com.android.compose.animation.scene.transformation.PropertyTransformation
-import com.android.compose.animation.scene.transformation.ScaleSize
 import com.android.compose.animation.scene.transformation.SharedElementTransformation
-import com.android.compose.animation.scene.transformation.Transformation
+import com.android.compose.animation.scene.transformation.TransformationMatcher
 import com.android.compose.animation.scene.transformation.TransformationWithRange
-import com.android.compose.animation.scene.transformation.Translate
 
 /** The transitions configuration of a [SceneTransitionLayout]. */
 class SceneTransitions
@@ -169,7 +161,7 @@
 }
 
 /** The definition of a transition between [from] and [to]. */
-interface TransitionSpec {
+internal interface TransitionSpec {
     /** The key of this [TransitionSpec]. */
     val key: TransitionKey?
 
@@ -209,7 +201,7 @@
     fun previewTransformationSpec(transition: TransitionState.Transition): TransformationSpec?
 }
 
-interface TransformationSpec {
+internal interface TransformationSpec {
     /**
      * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
      * the transition is triggered (i.e. it is not gesture-based).
@@ -232,8 +224,8 @@
      */
     val distance: UserActionDistance?
 
-    /** The list of [Transformation] applied to elements during this transition. */
-    val transformations: List<TransformationWithRange<*>>
+    /** The list of [TransformationMatcher] applied to elements during this transformation. */
+    val transformationMatchers: List<TransformationMatcher>
 
     companion object {
         internal val Empty =
@@ -241,7 +233,7 @@
                 progressSpec = snap(),
                 swipeSpec = null,
                 distance = null,
-                transformations = emptyList(),
+                transformationMatchers = emptyList(),
             )
         internal val EmptyProvider = { _: TransitionState.Transition -> Empty }
     }
@@ -272,7 +264,14 @@
                     progressSpec = reverse.progressSpec,
                     swipeSpec = reverse.swipeSpec,
                     distance = reverse.distance,
-                    transformations = reverse.transformations.map { it.reversed() },
+                    transformationMatchers =
+                        reverse.transformationMatchers.map {
+                            TransformationMatcher(
+                                matcher = it.matcher,
+                                factory = it.factory,
+                                range = it.range?.reversed(),
+                            )
+                        },
                 )
             },
         )
@@ -288,7 +287,7 @@
 }
 
 /** The definition of the overscroll behavior of the [content]. */
-interface OverscrollSpec {
+internal interface OverscrollSpec {
     /** The scene we are over scrolling. */
     val content: ContentKey
 
@@ -325,7 +324,7 @@
     override val progressSpec: AnimationSpec<Float>,
     override val swipeSpec: SpringSpec<Float>?,
     override val distance: UserActionDistance?,
-    override val transformations: List<TransformationWithRange<*>>,
+    override val transformationMatchers: List<TransformationMatcher>,
 ) : TransformationSpec {
     private val cache = mutableMapOf<ElementKey, MutableMap<ContentKey, ElementTransformations>>()
 
@@ -335,7 +334,7 @@
             .getOrPut(content) { computeTransformations(element, content) }
     }
 
-    /** Filter [transformations] to compute the [ElementTransformations] of [element]. */
+    /** Filter [transformationMatchers] to compute the [ElementTransformations] of [element]. */
     private fun computeTransformations(
         element: ElementKey,
         content: ContentKey,
@@ -346,48 +345,56 @@
         var drawScale: TransformationWithRange<PropertyTransformation<Scale>>? = null
         var alpha: TransformationWithRange<PropertyTransformation<Float>>? = null
 
-        transformations.fastForEach { transformationWithRange ->
-            val transformation = transformationWithRange.transformation
-            if (!transformation.matcher.matches(element, content)) {
+        transformationMatchers.fastForEach { transformationMatcher ->
+            if (!transformationMatcher.matcher.matches(element, content)) {
                 return@fastForEach
             }
 
-            when (transformation) {
-                is SharedElementTransformation -> {
-                    throwIfNotNull(shared, element, name = "shared")
-                    shared =
-                        transformationWithRange
-                            as TransformationWithRange<SharedElementTransformation>
+            val transformation = transformationMatcher.factory.create()
+            val property =
+                when (transformation) {
+                    is SharedElementTransformation -> {
+                        throwIfNotNull(shared, element, name = "shared")
+                        shared =
+                            TransformationWithRange(transformation, transformationMatcher.range)
+                        return@fastForEach
+                    }
+                    is PropertyTransformation<*> -> transformation.property
                 }
-                is Translate,
-                is OverscrollTranslate,
-                is EdgeTranslate,
-                is AnchoredTranslate -> {
+
+            when (property) {
+                is PropertyTransformation.Property.Offset -> {
                     throwIfNotNull(offset, element, name = "offset")
                     offset =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<Offset>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<Offset>,
+                            transformationMatcher.range,
+                        )
                 }
-                is ScaleSize,
-                is AnchoredSize -> {
+                is PropertyTransformation.Property.Size -> {
                     throwIfNotNull(size, element, name = "size")
                     size =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<IntSize>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<IntSize>,
+                            transformationMatcher.range,
+                        )
                 }
-                is DrawScale -> {
+                is PropertyTransformation.Property.Scale -> {
                     throwIfNotNull(drawScale, element, name = "drawScale")
                     drawScale =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<Scale>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<Scale>,
+                            transformationMatcher.range,
+                        )
                 }
-                is Fade -> {
+                is PropertyTransformation.Property.Alpha -> {
                     throwIfNotNull(alpha, element, name = "alpha")
                     alpha =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<Float>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<Float>,
+                            transformationMatcher.range,
+                        )
                 }
-                else -> error("Unknown transformation: $transformation")
             }
         }
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index f0043e1..dbfeb5c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -24,7 +24,6 @@
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified
 import kotlin.math.absoluteValue
@@ -66,8 +65,9 @@
         val absoluteDistance =
             with(animation.contentTransition.transformationSpec.distance ?: DefaultSwipeDistance) {
                 layoutImpl.userActionDistanceScope.absoluteDistance(
-                    layoutImpl.content(animation.fromContent).targetSize,
-                    orientation,
+                    fromContent = animation.fromContent,
+                    toContent = animation.toContent,
+                    orientation = orientation,
                 )
             }
 
@@ -475,12 +475,14 @@
 
 private object DefaultSwipeDistance : UserActionDistance {
     override fun UserActionDistanceScope.absoluteDistance(
-        fromSceneSize: IntSize,
+        fromContent: ContentKey,
+        toContent: ContentKey,
         orientation: Orientation,
     ): Float {
+        val fromContentSize = checkNotNull(fromContent.targetSize())
         return when (orientation) {
-            Orientation.Horizontal -> fromSceneSize.width
-            Orientation.Vertical -> fromSceneSize.height
+            Orientation.Horizontal -> fromContentSize.width
+            Orientation.Vertical -> fromContentSize.height
         }.toFloat()
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index a448ee4..5ab306a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -165,8 +165,7 @@
 
     private val nestedScrollHandlerImpl =
         NestedScrollHandlerImpl(
-            layoutImpl = draggableHandler.layoutImpl,
-            orientation = draggableHandler.orientation,
+            draggableHandler = draggableHandler,
             topOrLeftBehavior = NestedScrollBehavior.Default,
             bottomOrRightBehavior = NestedScrollBehavior.Default,
             isExternalOverscrollGesture = { false },
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index dc26b6b..48f08a7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -26,6 +26,7 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.Transformation
 import kotlin.math.tanh
 
 /** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
@@ -75,7 +76,7 @@
         preview: (TransitionBuilder.() -> Unit)? = null,
         reversePreview: (TransitionBuilder.() -> Unit)? = null,
         builder: TransitionBuilder.() -> Unit = {},
-    ): TransitionSpec
+    )
 
     /**
      * Define the animation to be played when transitioning [from] the specified content. For the
@@ -101,7 +102,7 @@
         preview: (TransitionBuilder.() -> Unit)? = null,
         reversePreview: (TransitionBuilder.() -> Unit)? = null,
         builder: TransitionBuilder.() -> Unit = {},
-    ): TransitionSpec
+    )
 
     /**
      * Define the animation to be played when the [content] is overscrolled in the given
@@ -114,13 +115,13 @@
         content: ContentKey,
         orientation: Orientation,
         builder: OverscrollBuilder.() -> Unit,
-    ): OverscrollSpec
+    )
 
     /**
      * Prevents overscroll the [content] in the given [orientation], allowing ancestors to
      * eventually consume the remaining gesture.
      */
-    fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec
+    fun overscrollDisabled(content: ContentKey, orientation: Orientation)
 }
 
 interface BaseTransitionBuilder : PropertyTransformationBuilder {
@@ -527,6 +528,9 @@
         anchorWidth: Boolean = true,
         anchorHeight: Boolean = true,
     )
+
+    /** Apply a [transformation] to the element(s) matching [matcher]. */
+    fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory)
 }
 
 /** This converter lets you change a linear progress into a function of your choice. */
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index e461f9c..6742b32 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -37,8 +37,8 @@
 import com.android.compose.animation.scene.transformation.ScaleSize
 import com.android.compose.animation.scene.transformation.SharedElementTransformation
 import com.android.compose.animation.scene.transformation.Transformation
+import com.android.compose.animation.scene.transformation.TransformationMatcher
 import com.android.compose.animation.scene.transformation.TransformationRange
-import com.android.compose.animation.scene.transformation.TransformationWithRange
 import com.android.compose.animation.scene.transformation.Translate
 
 internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
@@ -66,8 +66,8 @@
         preview: (TransitionBuilder.() -> Unit)?,
         reversePreview: (TransitionBuilder.() -> Unit)?,
         builder: TransitionBuilder.() -> Unit,
-    ): TransitionSpec {
-        return transition(from = null, to = to, key = key, preview, reversePreview, builder)
+    ) {
+        transition(from = null, to = to, key = key, preview, reversePreview, builder)
     }
 
     override fun from(
@@ -77,25 +77,25 @@
         preview: (TransitionBuilder.() -> Unit)?,
         reversePreview: (TransitionBuilder.() -> Unit)?,
         builder: TransitionBuilder.() -> Unit,
-    ): TransitionSpec {
-        return transition(from = from, to = to, key = key, preview, reversePreview, builder)
+    ) {
+        transition(from = from, to = to, key = key, preview, reversePreview, builder)
     }
 
     override fun overscroll(
         content: ContentKey,
         orientation: Orientation,
         builder: OverscrollBuilder.() -> Unit,
-    ): OverscrollSpec {
+    ) {
         val impl = OverscrollBuilderImpl().apply(builder)
-        check(impl.transformations.isNotEmpty()) {
+        check(impl.transformationMatchers.isNotEmpty()) {
             "This method does not allow empty transformations. " +
                 "Use overscrollDisabled($content, $orientation) instead."
         }
-        return overscrollSpec(content, orientation, impl)
+        overscrollSpec(content, orientation, impl)
     }
 
-    override fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec {
-        return overscrollSpec(content, orientation, OverscrollBuilderImpl())
+    override fun overscrollDisabled(content: ContentKey, orientation: Orientation) {
+        overscrollSpec(content, orientation, OverscrollBuilderImpl())
     }
 
     private fun overscrollSpec(
@@ -112,7 +112,7 @@
                         progressSpec = snap(),
                         swipeSpec = null,
                         distance = impl.distance,
-                        transformations = impl.transformations,
+                        transformationMatchers = impl.transformationMatchers,
                     ),
                 progressConverter = impl.progressConverter,
             )
@@ -137,7 +137,7 @@
                 progressSpec = impl.spec,
                 swipeSpec = impl.swipeSpec,
                 distance = impl.distance,
-                transformations = impl.transformations,
+                transformationMatchers = impl.transformationMatchers,
             )
         }
 
@@ -157,7 +157,7 @@
 }
 
 internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder {
-    val transformations = mutableListOf<TransformationWithRange<*>>()
+    val transformationMatchers = mutableListOf<TransformationMatcher>()
     private var range: TransformationRange? = null
     protected var reversed = false
     override var distance: UserActionDistance? = null
@@ -173,23 +173,31 @@
         range = null
     }
 
-    protected fun transformation(transformation: Transformation) {
-        val transformationWithRange = TransformationWithRange(transformation, range)
-        transformations.add(
-            if (reversed) {
-                transformationWithRange.reversed()
-            } else {
-                transformationWithRange
-            }
+    protected fun addTransformation(
+        matcher: ElementMatcher,
+        transformation: Transformation.Factory,
+    ) {
+        transformationMatchers.add(
+            TransformationMatcher(
+                matcher,
+                transformation,
+                range?.let { range ->
+                    if (reversed) {
+                        range.reversed()
+                    } else {
+                        range
+                    }
+                },
+            )
         )
     }
 
     override fun fade(matcher: ElementMatcher) {
-        transformation(Fade(matcher))
+        addTransformation(matcher, Fade.Factory)
     }
 
     override fun translate(matcher: ElementMatcher, x: Dp, y: Dp) {
-        transformation(Translate(matcher, x, y))
+        addTransformation(matcher, Translate.Factory(x, y))
     }
 
     override fun translate(
@@ -197,19 +205,19 @@
         edge: Edge,
         startsOutsideLayoutBounds: Boolean,
     ) {
-        transformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds))
+        addTransformation(matcher, EdgeTranslate.Factory(edge, startsOutsideLayoutBounds))
     }
 
     override fun anchoredTranslate(matcher: ElementMatcher, anchor: ElementKey) {
-        transformation(AnchoredTranslate(matcher, anchor))
+        addTransformation(matcher, AnchoredTranslate.Factory(anchor))
     }
 
     override fun scaleSize(matcher: ElementMatcher, width: Float, height: Float) {
-        transformation(ScaleSize(matcher, width, height))
+        addTransformation(matcher, ScaleSize.Factory(width, height))
     }
 
     override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) {
-        transformation(DrawScale(matcher, scaleX, scaleY, pivot))
+        addTransformation(matcher, DrawScale.Factory(scaleX, scaleY, pivot))
     }
 
     override fun anchoredSize(
@@ -218,7 +226,12 @@
         anchorWidth: Boolean,
         anchorHeight: Boolean,
     ) {
-        transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
+        addTransformation(matcher, AnchoredSize.Factory(anchor, anchorWidth, anchorHeight))
+    }
+
+    override fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory) {
+        check(range == null) { "Custom transformations can not be applied inside a range" }
+        addTransformation(matcher, transformation)
     }
 }
 
@@ -257,7 +270,10 @@
                 "(${transition.toContent.debugName})"
         }
 
-        transformation(SharedElementTransformation(matcher, enabled, elevateInContent))
+        addTransformation(
+            matcher,
+            SharedElementTransformation.Factory(matcher, enabled, elevateInContent),
+        )
     }
 
     override fun timestampRange(
@@ -288,6 +304,6 @@
         x: OverscrollScope.() -> Float,
         y: OverscrollScope.() -> Float,
     ) {
-        transformation(OverscrollTranslate(matcher, x, y))
+        addTransformation(matcher, OverscrollTranslate.Factory(x, y))
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 8187e39..255a16c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -16,7 +16,7 @@
 
 package com.android.compose.animation.scene.content
 
-import androidx.compose.foundation.gestures.Orientation
+import android.annotation.SuppressLint
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Stable
@@ -72,6 +72,7 @@
     var targetSize by mutableStateOf(IntSize.Zero)
     var userActions by mutableStateOf(actions)
 
+    @SuppressLint("NotConstructor")
     @Composable
     fun Content(modifier: Modifier = Modifier) {
         Box(
@@ -151,8 +152,7 @@
         isExternalOverscrollGesture: () -> Boolean,
     ): Modifier {
         return nestedScrollToScene(
-            layoutImpl = layoutImpl,
-            orientation = Orientation.Horizontal,
+            draggableHandler = layoutImpl.horizontalDraggableHandler,
             topOrLeftBehavior = leftBehavior,
             bottomOrRightBehavior = rightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
@@ -165,8 +165,7 @@
         isExternalOverscrollGesture: () -> Boolean,
     ): Modifier {
         return nestedScrollToScene(
-            layoutImpl = layoutImpl,
-            orientation = Orientation.Vertical,
+            draggableHandler = layoutImpl.verticalDraggableHandler,
             topOrLeftBehavior = topBehavior,
             bottomOrRightBehavior = bottomBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index e3118d67..33f015f 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -35,6 +35,8 @@
 import com.android.compose.animation.scene.TransformationSpec
 import com.android.compose.animation.scene.TransformationSpecImpl
 import com.android.compose.animation.scene.TransitionKey
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 
 /** The state associated to a [SceneTransitionLayout] at some specific point in time. */
@@ -128,7 +130,7 @@
              * starting a swipe transition to show [overlay] and will be `true` only once the swipe
              * transition is committed.
              */
-            protected abstract val isEffectivelyShown: Boolean
+            abstract val isEffectivelyShown: Boolean
 
             init {
                 check(
@@ -163,7 +165,7 @@
              * [fromOverlay] by [toOverlay] and will [toOverlay] once the swipe transition is
              * committed.
              */
-            protected abstract val effectivelyShownOverlay: OverlayKey
+            abstract val effectivelyShownOverlay: OverlayKey
 
             init {
                 check(fromOverlay != toOverlay)
@@ -279,8 +281,24 @@
          */
         private var interruptionDecay: Animatable<Float, AnimationVector1D>? = null
 
-        /** Whether this transition was already started. */
-        private var wasStarted = false
+        /**
+         * The coroutine scope associated to this transition.
+         *
+         * This coroutine scope can be used to launch animations associated to this transition,
+         * which will not finish until at least one animation/job is still running in the scope.
+         *
+         * Important: Make sure to never launch long-running jobs in this scope, otherwise the
+         * transition will never be considered as finished.
+         */
+        internal val coroutineScope: CoroutineScope
+            get() =
+                _coroutineScope
+                    ?: error(
+                        "Transition.coroutineScope can only be accessed once the transition was " +
+                            "started "
+                    )
+
+        private var _coroutineScope: CoroutineScope? = null
 
         init {
             check(fromContent != toContent)
@@ -326,6 +344,21 @@
             }
         }
 
+        /** Whether [fromContent] is effectively the current content of the transition. */
+        internal fun isFromCurrentContent() = isCurrentContent(expectedFrom = true)
+
+        /** Whether [toContent] is effectively the current content of the transition. */
+        internal fun isToCurrentContent() = isCurrentContent(expectedFrom = false)
+
+        private fun isCurrentContent(expectedFrom: Boolean): Boolean {
+            val expectedContent = if (expectedFrom) fromContent else toContent
+            return when (this) {
+                is ChangeScene -> currentScene == expectedContent
+                is ReplaceOverlay -> effectivelyShownOverlay == expectedContent
+                is ShowOrHideOverlay -> isEffectivelyShown == (expectedContent == overlay)
+            }
+        }
+
         /** Run this transition and return once it is finished. */
         protected abstract suspend fun run()
 
@@ -341,10 +374,11 @@
         abstract fun freezeAndAnimateToCurrentState()
 
         internal suspend fun runInternal() {
-            check(!wasStarted) { "A Transition can be started only once." }
-            wasStarted = true
-
-            run()
+            check(_coroutineScope == null) { "A Transition can be started only once." }
+            coroutineScope {
+                _coroutineScope = this
+                run()
+            }
         }
 
         internal fun updateOverscrollSpecs(
@@ -367,7 +401,7 @@
                     else -> null
                 } ?: return true
 
-            return specForCurrentScene.transformationSpec.transformations.isNotEmpty()
+            return specForCurrentScene.transformationSpec.transformationMatchers.isNotEmpty()
         }
 
         internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
new file mode 100644
index 0000000..bfb5ca7
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.reveal
+
+import androidx.compose.animation.core.AnimationVector1D
+import androidx.compose.animation.core.DeferredTargetAnimation
+import androidx.compose.animation.core.ExperimentalAnimatableApi
+import androidx.compose.animation.core.FiniteAnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.spring
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastCoerceAtLeast
+import androidx.compose.ui.util.fastCoerceAtMost
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.OverlayKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.UserActionDistance
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
+
+interface ContainerRevealHaptics {
+    /**
+     * Called when the reveal threshold is crossed while the user was dragging on screen.
+     *
+     * Important: This callback is called during layout and its implementation should therefore be
+     * very fast or posted to a different thread.
+     *
+     * @param revealed whether we go from hidden to revealed, i.e. whether the container size is
+     *   going to jump from a smaller size to a bigger size.
+     */
+    fun onRevealThresholdCrossed(revealed: Boolean)
+}
+
+/** Animate the reveal of [container] by animating its size. */
+fun TransitionBuilder.verticalContainerReveal(
+    container: ElementKey,
+    haptics: ContainerRevealHaptics,
+) {
+    // Make the swipe distance be exactly the target height of the container.
+    // TODO(b/376438969): Make sure that this works correctly when the target size of the element
+    // is changing during the transition (e.g. a notification was added). At the moment, the user
+    // action distance is only called until it returns a value > 0f, which is then cached.
+    distance = UserActionDistance { fromContent, toContent, _ ->
+        val targetSizeInFromContent = container.targetSize(fromContent)
+        val targetSizeInToContent = container.targetSize(toContent)
+        if (targetSizeInFromContent != null && targetSizeInToContent != null) {
+            error(
+                "verticalContainerReveal should not be used with shared elements, but " +
+                    "${container.debugName} is in both ${fromContent.debugName} and " +
+                    toContent.debugName
+            )
+        }
+
+        (targetSizeInToContent?.height ?: targetSizeInFromContent?.height)?.toFloat() ?: 0f
+    }
+
+    // TODO(b/376438969): Improve the motion of this gesture using Motion Mechanics.
+
+    // The min distance to swipe before triggering the reveal spring.
+    val distanceThreshold = 80.dp
+
+    // The minimum height of the container.
+    val minHeight = 10.dp
+
+    // The amount removed from the container width at 0% progress.
+    val widthDelta = 140.dp
+
+    // The ratio at which the distance is tracked before reaching the threshold, e.g. if the user
+    // drags 60dp then the height will be 60dp * 0.25f = 15dp.
+    val trackingRatio = 0.25f
+
+    // The max progress starting from which the container should always be visible, even if we are
+    // animating the container out. This is used so that we don't immediately fade out the container
+    // when triggering a one-off animation that hides it.
+    val alphaProgressThreshold = 0.05f
+
+    // The spring animating the size of the container.
+    val sizeSpec = spring<Float>(stiffness = 380f, dampingRatio = 0.9f)
+
+    // The spring animating the alpha of the container.
+    val alphaSpec = spring<Float>(stiffness = 1200f, dampingRatio = 0.99f)
+
+    // The spring animating the progress when releasing the finger.
+    swipeSpec =
+        spring(
+            stiffness = Spring.StiffnessMediumLow,
+            dampingRatio = Spring.DampingRatioNoBouncy,
+            visibilityThreshold = 0.5f,
+        )
+
+    // Size transformation.
+    transformation(container) {
+        VerticalContainerRevealSizeTransformation(
+            haptics,
+            distanceThreshold,
+            trackingRatio,
+            minHeight,
+            widthDelta,
+            sizeSpec,
+        )
+    }
+
+    // Alpha transformation.
+    transformation(container) {
+        ContainerRevealAlphaTransformation(alphaSpec, alphaProgressThreshold)
+    }
+}
+
+@OptIn(ExperimentalAnimatableApi::class)
+private class VerticalContainerRevealSizeTransformation(
+    private val haptics: ContainerRevealHaptics,
+    private val distanceThreshold: Dp,
+    private val trackingRatio: Float,
+    private val minHeight: Dp,
+    private val widthDelta: Dp,
+    private val spec: FiniteAnimationSpec<Float>,
+) : CustomPropertyTransformation<IntSize> {
+    override val property = PropertyTransformation.Property.Size
+
+    private val widthAnimation = DeferredTargetAnimation(Float.VectorConverter)
+    private val heightAnimation = DeferredTargetAnimation(Float.VectorConverter)
+
+    private var previousHasReachedThreshold: Boolean? = null
+
+    override fun PropertyTransformationScope.transform(
+        content: ContentKey,
+        element: ElementKey,
+        transition: TransitionState.Transition,
+        transitionScope: CoroutineScope,
+    ): IntSize {
+        // The distance to go to 100%. Note that we don't use
+        // TransitionState.HasOverscrollProperties.absoluteDistance because the transition will not
+        // implement HasOverscrollProperties if the transition is triggered and not gesture based.
+        val idleSize = checkNotNull(element.targetSize(content))
+        val userActionDistance = idleSize.height
+        val progress =
+            when ((transition as? TransitionState.HasOverscrollProperties)?.bouncingContent) {
+                null -> transition.progressTo(content)
+                content -> 1f
+                else -> 0f
+            }
+        val distance = (progress * userActionDistance).fastCoerceAtLeast(0f)
+        val threshold = distanceThreshold.toPx()
+
+        // Width.
+        val widthDelta = widthDelta.toPx()
+        val width =
+            (idleSize.width - widthDelta +
+                    animateSize(
+                        size = widthDelta,
+                        distance = distance,
+                        threshold = threshold,
+                        transitionScope = transitionScope,
+                        animation = widthAnimation,
+                    ))
+                .roundToInt()
+
+        // Height.
+        val minHeight = minHeight.toPx()
+        val height =
+            (
+                // 1) The minimum size of the container.
+                minHeight +
+
+                    // 2) The animated size between the minimum size and the threshold.
+                    animateSize(
+                        size = threshold - minHeight,
+                        distance = distance,
+                        threshold = threshold,
+                        transitionScope = transitionScope,
+                        animation = heightAnimation,
+                    ) +
+
+                    // 3) The remaining height after the threshold, tracking the finger.
+                    (distance - threshold).fastCoerceAtLeast(0f))
+                .roundToInt()
+                .fastCoerceAtMost(idleSize.height)
+
+        // Haptics.
+        val hasReachedThreshold = distance >= threshold
+        if (
+            previousHasReachedThreshold != null &&
+                hasReachedThreshold != previousHasReachedThreshold &&
+                transition.isUserInputOngoing
+        ) {
+            haptics.onRevealThresholdCrossed(revealed = hasReachedThreshold)
+        }
+        previousHasReachedThreshold = hasReachedThreshold
+
+        return IntSize(width = width, height = height)
+    }
+
+    /**
+     * Animate a size up to [size], so that it is equal to 0f when distance is 0f and equal to
+     * [size] when `distance >= threshold`, taking the [trackingRatio] into account.
+     */
+    @OptIn(ExperimentalAnimatableApi::class)
+    private fun animateSize(
+        size: Float,
+        distance: Float,
+        threshold: Float,
+        transitionScope: CoroutineScope,
+        animation: DeferredTargetAnimation<Float, AnimationVector1D>,
+    ): Float {
+        val trackingSize = distance.fastCoerceAtMost(threshold) / threshold * size * trackingRatio
+        val springTarget =
+            if (distance >= threshold) {
+                size * (1f - trackingRatio)
+            } else {
+                0f
+            }
+        val springSize = animation.updateTarget(springTarget, transitionScope, spec)
+        return trackingSize + springSize
+    }
+}
+
+@OptIn(ExperimentalAnimatableApi::class)
+private class ContainerRevealAlphaTransformation(
+    private val spec: FiniteAnimationSpec<Float>,
+    private val progressThreshold: Float,
+) : CustomPropertyTransformation<Float> {
+    override val property = PropertyTransformation.Property.Alpha
+    private val alphaAnimation = DeferredTargetAnimation(Float.VectorConverter)
+
+    override fun PropertyTransformationScope.transform(
+        content: ContentKey,
+        element: ElementKey,
+        transition: TransitionState.Transition,
+        transitionScope: CoroutineScope,
+    ): Float {
+        return alphaAnimation.updateTarget(targetAlpha(transition, content), transitionScope, spec)
+    }
+
+    private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float {
+        if (transition.isUserInputOngoing) {
+            if (transition !is TransitionState.HasOverscrollProperties) {
+                error(
+                    "Unsupported transition driven by user input but that does not have " +
+                        "overscroll properties: $transition"
+                )
+            }
+
+            val bouncingContent = transition.bouncingContent
+            return if (bouncingContent != null) {
+                if (bouncingContent == content) 1f else 0f
+            } else {
+                if (transition.progressTo(content) > 0f) 1f else 0f
+            }
+        }
+
+        // The transition was committed (the user released their finger), so the alpha depends on
+        // whether we are animating towards the content (showing the container) or away from it
+        // (hiding the container).
+        val isShowingContainer =
+            when (content) {
+                is SceneKey -> transition.currentScene == content
+                is OverlayKey -> transition.currentOverlays.contains(content)
+            }
+
+        return if (isShowingContainer || transition.progressTo(content) >= progressThreshold) {
+            1f
+        } else {
+            0f
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
index 0ddeb7c..6575068 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
@@ -19,16 +19,17 @@
 import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.content.state.TransitionState
 
 /** Anchor the size of an element to the size of another element. */
-internal class AnchoredSize(
-    override val matcher: ElementMatcher,
+internal class AnchoredSize
+private constructor(
     private val anchor: ElementKey,
     private val anchorWidth: Boolean,
     private val anchorHeight: Boolean,
-) : PropertyTransformation<IntSize> {
+) : InterpolatedPropertyTransformation<IntSize> {
+    override val property = PropertyTransformation.Property.Size
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -59,4 +60,12 @@
             anchorSizeIn(transition.fromContent)
         }
     }
+
+    class Factory(
+        private val anchor: ElementKey,
+        private val anchorWidth: Boolean,
+        private val anchorHeight: Boolean,
+    ) : Transformation.Factory {
+        override fun create(): Transformation = AnchoredSize(anchor, anchorWidth, anchorHeight)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
index 47508b4..890902b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
@@ -19,14 +19,13 @@
 import androidx.compose.ui.geometry.Offset
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.content.state.TransitionState
 
 /** Anchor the translation of an element to another element. */
-internal class AnchoredTranslate(
-    override val matcher: ElementMatcher,
-    private val anchor: ElementKey,
-) : PropertyTransformation<Offset> {
+internal class AnchoredTranslate private constructor(private val anchor: ElementKey) :
+    InterpolatedPropertyTransformation<Offset> {
+    override val property = PropertyTransformation.Property.Offset
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -56,6 +55,10 @@
             Offset(idleValue.x + offset.x, idleValue.y + offset.y)
         }
     }
+
+    class Factory(private val anchor: ElementKey) : Transformation.Factory {
+        override fun create(): Transformation = AnchoredTranslate(anchor)
+    }
 }
 
 internal fun throwMissingAnchorException(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
index 8488ae5..347f1c3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
@@ -19,7 +19,6 @@
 import androidx.compose.ui.geometry.Offset
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.Scale
 import com.android.compose.animation.scene.content.state.TransitionState
 
@@ -27,12 +26,14 @@
  * Scales the draw size of an element. Note this will only scale the draw inside of an element,
  * therefore it won't impact layout of elements around it.
  */
-internal class DrawScale(
-    override val matcher: ElementMatcher,
+internal class DrawScale
+private constructor(
     private val scaleX: Float,
     private val scaleY: Float,
-    private val pivot: Offset = Offset.Unspecified,
-) : PropertyTransformation<Scale> {
+    private val pivot: Offset,
+) : InterpolatedPropertyTransformation<Scale> {
+    override val property = PropertyTransformation.Property.Scale
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -41,4 +42,9 @@
     ): Scale {
         return Scale(scaleX, scaleY, pivot)
     }
+
+    class Factory(private val scaleX: Float, private val scaleY: Float, private val pivot: Offset) :
+        Transformation.Factory {
+        override fun create(): Transformation = DrawScale(scaleX, scaleY, pivot)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
index 884aae4b..f8e6dc0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
@@ -20,15 +20,14 @@
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.content.state.TransitionState
 
 /** Translate an element from an edge of the layout. */
-internal class EdgeTranslate(
-    override val matcher: ElementMatcher,
-    private val edge: Edge,
-    private val startsOutsideLayoutBounds: Boolean = true,
-) : PropertyTransformation<Offset> {
+internal class EdgeTranslate
+private constructor(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) :
+    InterpolatedPropertyTransformation<Offset> {
+    override val property = PropertyTransformation.Property.Offset
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -67,4 +66,9 @@
                 }
         }
     }
+
+    class Factory(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) :
+        Transformation.Factory {
+        override fun create(): Transformation = EdgeTranslate(edge, startsOutsideLayoutBounds)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
index ef769e7..d92419e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
@@ -18,11 +18,12 @@
 
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.content.state.TransitionState
 
 /** Fade an element in or out. */
-internal class Fade(override val matcher: ElementMatcher) : PropertyTransformation<Float> {
+internal object Fade : InterpolatedPropertyTransformation<Float> {
+    override val property = PropertyTransformation.Property.Alpha
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -33,4 +34,8 @@
         // fading out, which is `0` in both cases.
         return 0f
     }
+
+    object Factory : Transformation.Factory {
+        override fun create(): Transformation = Fade
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
index ef3654b..5d31fd9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
@@ -19,7 +19,6 @@
 import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.content.state.TransitionState
 import kotlin.math.roundToInt
 
@@ -27,11 +26,10 @@
  * Scales the size of an element. Note that this makes the element resize every frame and will
  * therefore impact the layout of other elements.
  */
-internal class ScaleSize(
-    override val matcher: ElementMatcher,
-    private val width: Float = 1f,
-    private val height: Float = 1f,
-) : PropertyTransformation<IntSize> {
+internal class ScaleSize private constructor(private val width: Float, private val height: Float) :
+    InterpolatedPropertyTransformation<IntSize> {
+    override val property = PropertyTransformation.Property.Size
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -43,4 +41,9 @@
             height = (idleValue.height * height).roundToInt(),
         )
     }
+
+    class Factory(private val width: Float = 1f, private val height: Float = 1f) :
+        Transformation.Factory {
+        override fun create(): Transformation = ScaleSize(width, height)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 74a3ead..e0b4218 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -18,7 +18,9 @@
 
 import androidx.compose.animation.core.Easing
 import androidx.compose.animation.core.LinearEasing
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.util.fastCoerceAtLeast
 import androidx.compose.ui.util.fastCoerceAtMost
@@ -27,30 +29,65 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.ElementStateScope
+import com.android.compose.animation.scene.Scale
 import com.android.compose.animation.scene.content.state.TransitionState
+import kotlinx.coroutines.CoroutineScope
 
 /** A transformation applied to one or more elements during a transition. */
 sealed interface Transformation {
-    /**
-     * The matcher that should match the element(s) to which this transformation should be applied.
-     */
-    val matcher: ElementMatcher
-
-    /*
-     * Reverse this transformation. This is called when we use Transition(from = A, to = B) when
-     * animating from B to A and there is no Transition(from = B, to = A) defined.
-     */
-    fun reversed(): Transformation = this
+    fun interface Factory {
+        fun create(): Transformation
+    }
 }
 
-internal class SharedElementTransformation(
-    override val matcher: ElementMatcher,
+// Important: SharedElementTransformation must be a data class because we check that we don't
+// provide 2 different transformations for the same element in Element.kt
+internal data class SharedElementTransformation(
     internal val enabled: Boolean,
     internal val elevateInContent: ContentKey?,
-) : Transformation
+) : Transformation {
+    class Factory(
+        internal val matcher: ElementMatcher,
+        internal val enabled: Boolean,
+        internal val elevateInContent: ContentKey?,
+    ) : Transformation.Factory {
+        override fun create(): Transformation {
+            return SharedElementTransformation(enabled, elevateInContent)
+        }
+    }
+}
 
-/** A transformation that changes the value of an element property, like its size or offset. */
-interface PropertyTransformation<T> : Transformation {
+/**
+ * A transformation that changes the value of an element [Property], like its [size][Property.Size]
+ * or [offset][Property.Offset].
+ */
+sealed interface PropertyTransformation<T> : Transformation {
+    /** The property to which this transformation is applied. */
+    val property: Property<T>
+
+    sealed class Property<T> {
+        /** The size of an element. */
+        data object Size : Property<IntSize>()
+
+        /** The offset (position) of an element. */
+        data object Offset : Property<androidx.compose.ui.geometry.Offset>()
+
+        /** The alpha of an element. */
+        data object Alpha : Property<Float>()
+
+        /**
+         * The drawing scale of an element. Animating the scale does not have any effect on the
+         * layout.
+         */
+        data object Scale : Property<com.android.compose.animation.scene.Scale>()
+    }
+}
+
+/**
+ * A transformation to a target/transformed value that is automatically interpolated using the
+ * transition progress and transformation range.
+ */
+interface InterpolatedPropertyTransformation<T> : PropertyTransformation<T> {
     /**
      * Return the transformed value for the given property, i.e.:
      * - the value at progress = 0% for elements that are entering the layout (i.e. elements in the
@@ -58,8 +95,8 @@
      * - the value at progress = 100% for elements that are leaving the layout (i.e. elements in the
      *   content we are transitioning from).
      *
-     * The returned value will be interpolated using the [transition] progress and [idleValue], the
-     * value of the property when we are idle.
+     * The returned value will be automatically interpolated using the [transition] progress, the
+     * transformation range and [idleValue], the value of the property when we are idle.
      */
     fun PropertyTransformationScope.transform(
         content: ContentKey,
@@ -69,13 +106,40 @@
     ): T
 }
 
+interface CustomPropertyTransformation<T> : PropertyTransformation<T> {
+    /**
+     * Return the value that the property should have in the current frame for the given [content]
+     * and [element].
+     *
+     * This transformation can use [transitionScope] to launch animations associated to
+     * [transition], which will not finish until at least one animation/job is still running in the
+     * scope.
+     *
+     * Important: Make sure to never launch long-running jobs in [transitionScope], otherwise
+     * [transition] will never be considered as finished.
+     */
+    fun PropertyTransformationScope.transform(
+        content: ContentKey,
+        element: ElementKey,
+        transition: TransitionState.Transition,
+        transitionScope: CoroutineScope,
+    ): T
+}
+
 interface PropertyTransformationScope : Density, ElementStateScope {
     /** The current [direction][LayoutDirection] of the layout. */
     val layoutDirection: LayoutDirection
 }
 
+/** Defines the transformation-type to be applied to all elements matching [matcher]. */
+internal class TransformationMatcher(
+    val matcher: ElementMatcher,
+    val factory: Transformation.Factory,
+    val range: TransformationRange?,
+)
+
 /** A pair consisting of a [transformation] and optional [range]. */
-class TransformationWithRange<out T : Transformation>(
+internal data class TransformationWithRange<out T : Transformation>(
     val transformation: T,
     val range: TransformationRange?,
 ) {
@@ -87,7 +151,7 @@
 }
 
 /** The progress-based range of a [PropertyTransformation]. */
-data class TransformationRange(val start: Float, val end: Float, val easing: Easing) {
+internal data class TransformationRange(val start: Float, val end: Float, val easing: Easing) {
     constructor(
         start: Float? = null,
         end: Float? = null,
@@ -101,7 +165,7 @@
     }
 
     /** Reverse this range. */
-    fun reversed() =
+    internal fun reversed() =
         TransformationRange(start = reverseBound(end), end = reverseBound(start), easing = easing)
 
     /** Get the progress of this range given the global [transitionProgress]. */
@@ -128,6 +192,6 @@
     }
 
     companion object {
-        const val BoundUnspecified = Float.MIN_VALUE
+        internal const val BoundUnspecified = Float.MIN_VALUE
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
index 356ed99..2f4d5bff 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -19,18 +19,15 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.ElementMatcher
 import com.android.compose.animation.scene.OverscrollScope
 import com.android.compose.animation.scene.content.state.TransitionState
 
-internal class Translate(
-    override val matcher: ElementMatcher,
-    private val x: Dp = 0.dp,
-    private val y: Dp = 0.dp,
-) : PropertyTransformation<Offset> {
+internal class Translate private constructor(private val x: Dp, private val y: Dp) :
+    InterpolatedPropertyTransformation<Offset> {
+    override val property = PropertyTransformation.Property.Offset
+
     override fun PropertyTransformationScope.transform(
         content: ContentKey,
         element: ElementKey,
@@ -39,13 +36,19 @@
     ): Offset {
         return Offset(idleValue.x + x.toPx(), idleValue.y + y.toPx())
     }
+
+    class Factory(private val x: Dp, private val y: Dp) : Transformation.Factory {
+        override fun create(): Transformation = Translate(x, y)
+    }
 }
 
-internal class OverscrollTranslate(
-    override val matcher: ElementMatcher,
-    val x: OverscrollScope.() -> Float = { 0f },
-    val y: OverscrollScope.() -> Float = { 0f },
-) : PropertyTransformation<Offset> {
+internal class OverscrollTranslate
+private constructor(
+    private val x: OverscrollScope.() -> Float,
+    private val y: OverscrollScope.() -> Float,
+) : InterpolatedPropertyTransformation<Offset> {
+    override val property = PropertyTransformation.Property.Offset
+
     private val cachedOverscrollScope = CachedOverscrollScope()
 
     override fun PropertyTransformationScope.transform(
@@ -63,6 +66,13 @@
 
         return Offset(x = value.x + overscrollScope.x(), y = value.y + overscrollScope.y())
     }
+
+    class Factory(
+        private val x: OverscrollScope.() -> Float,
+        private val y: OverscrollScope.() -> Float,
+    ) : Transformation.Factory {
+        override fun create(): Transformation = OverscrollTranslate(x, y)
+    }
 }
 
 /**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 20a0b39..3f18236 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -365,12 +365,16 @@
         flingBehavior: FlingBehavior,
     ): Float {
         return with(flingBehavior) {
-            object : ScrollScope {
-                    override fun scrollBy(pixels: Float): Float {
-                        return controller.onScroll(pixels, NestedScrollSource.SideEffect)
+            val remainingVelocity =
+                object : ScrollScope {
+                        override fun scrollBy(pixels: Float): Float {
+                            return controller.onScroll(pixels, NestedScrollSource.SideEffect)
+                        }
                     }
-                }
-                .performFling(initialVelocity)
+                    .performFling(initialVelocity)
+
+            // returns the consumed velocity
+            initialVelocity - remainingVelocity
         }
     }
 }
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 7e6f3a8..10057b2 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
@@ -133,8 +133,8 @@
                 )
                 .apply { setContentsAndLayoutTargetSizeForTest(LAYOUT_SIZE) }
 
-        val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical)
-        val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
+        val draggableHandler = layoutImpl.verticalDraggableHandler
+        val horizontalDraggableHandler = layoutImpl.horizontalDraggableHandler
 
         var pointerInfoOwner: () -> PointersInfo = { pointersDown() }
 
@@ -143,8 +143,7 @@
             isExternalOverscrollGesture: Boolean = false,
         ) =
             NestedScrollHandlerImpl(
-                    layoutImpl = layoutImpl,
-                    orientation = draggableHandler.orientation,
+                    draggableHandler = draggableHandler,
                     topOrLeftBehavior = nestedScrollBehavior,
                     bottomOrRightBehavior = nestedScrollBehavior,
                     isExternalOverscrollGesture = { isExternalOverscrollGesture },
@@ -645,7 +644,7 @@
         mutableUserActionsA = emptyMap()
         mutableUserActionsB = emptyMap()
 
-        // start accelaratedScroll and scroll over to B -> null
+        // start acceleratedScroll and scroll over to B -> null
         val dragController2 = onDragStartedImmediately()
         dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f)
         dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f)
@@ -1531,7 +1530,7 @@
     fun interceptingTransitionKeepsDistance() = runGestureTest {
         var swipeDistance = 75f
         layoutState.transitions = transitions {
-            from(SceneA, to = SceneB) { distance = UserActionDistance { _, _ -> swipeDistance } }
+            from(SceneA, to = SceneB) { distance = UserActionDistance { _, _, _ -> swipeDistance } }
         }
 
         // Start transition.
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index 09b5939..b4c8ad7 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -35,6 +35,7 @@
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
 import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasTestTag
 import androidx.compose.ui.test.hasText
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onAllNodesWithText
@@ -404,4 +405,40 @@
         rule.waitForIdle()
         rule.onNodeWithTag(fooParentInOverlayTag).assertSizeIsEqualTo(fooSize)
     }
+
+    @Test
+    fun movableElementInOverlayShouldBeComposed() {
+        val fooKey = MovableElementKey("foo", contents = setOf(OverlayA))
+        val fooContentTag = "fooContentTag"
+
+        @Composable
+        fun ContentScope.MovableFoo(modifier: Modifier = Modifier) {
+            MovableElement(fooKey, modifier) {
+                content { Box(Modifier.testTag(fooContentTag).size(100.dp)) }
+            }
+        }
+
+        val state =
+            rule.runOnUiThread {
+                MutableSceneTransitionLayoutState(
+                    initialScene = SceneA,
+                    initialOverlays = setOf(OverlayA),
+                )
+            }
+
+        val scope =
+            rule.setContentAndCreateMainScope {
+                SceneTransitionLayout(state) {
+                    scene(SceneA) { Box(Modifier.fillMaxSize()) }
+                    overlay(OverlayA) { MovableFoo() }
+                    overlay(OverlayB) { Box(Modifier.size(50.dp)) }
+                }
+            }
+
+        rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)
+
+        // Show overlay B. This shouldn't have any impact on Foo that should still be composed in A.
+        scope.launch { state.startTransition(transition(SceneA, OverlayB)) }
+        rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp)
+    }
 }
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 2b70908..79ca891 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
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestOverlays.OverlayA
 import com.android.compose.animation.scene.TestScenes.SceneA
 import com.android.compose.animation.scene.TestScenes.SceneB
 import com.android.compose.animation.scene.TestScenes.SceneC
@@ -35,12 +36,15 @@
 import com.android.compose.test.transition
 import com.google.common.truth.Truth.assertThat
 import kotlin.coroutines.cancellation.CancellationException
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.consumeAsFlow
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertThrows
 import org.junit.Rule
@@ -149,7 +153,7 @@
 
         // Default transition from A to B.
         assertThat(state.setTargetScene(SceneB, animationScope = this)).isNotNull()
-        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
+        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1)
 
         // Go back to A.
         state.setTargetScene(SceneA, animationScope = this)
@@ -162,7 +166,7 @@
                 state.setTargetScene(SceneB, animationScope = this, transitionKey = transitionkey)
             )
             .isNotNull()
-        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
+        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
     }
 
     @Test
@@ -185,6 +189,25 @@
     }
 
     @Test
+    fun snapToIdleIfClose_snapToStart_overlays() = runMonotonicClockTest {
+        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+        state.startTransitionImmediately(
+            animationScope = backgroundScope,
+            transition(SceneA, OverlayA, isEffectivelyShown = { false }, progress = { 0.2f }),
+        )
+        assertThat(state.isTransitioning()).isTrue()
+
+        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+        assertThat(state.isTransitioning()).isTrue()
+
+        // Go to the initial scene if it is close to 0.
+        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+        assertThat(state.isTransitioning()).isFalse()
+        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA))
+    }
+
+    @Test
     fun snapToIdleIfClose_snapToEnd() = runMonotonicClockTest {
         val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
         state.startTransitionImmediately(
@@ -204,6 +227,25 @@
     }
 
     @Test
+    fun snapToIdleIfClose_snapToEnd_overlays() = runMonotonicClockTest {
+        val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
+        state.startTransitionImmediately(
+            animationScope = backgroundScope,
+            transition(SceneA, OverlayA, isEffectivelyShown = { true }, progress = { 0.8f }),
+        )
+        assertThat(state.isTransitioning()).isTrue()
+
+        // Ignore the request if the progress is not close to 0 or 1, using the threshold.
+        assertThat(state.snapToIdleIfClose(threshold = 0.1f)).isFalse()
+        assertThat(state.isTransitioning()).isTrue()
+
+        // Go to the final scene if it is close to 1.
+        assertThat(state.snapToIdleIfClose(threshold = 0.2f)).isTrue()
+        assertThat(state.isTransitioning()).isFalse()
+        assertThat(state.transitionState).isEqualTo(TransitionState.Idle(SceneA, setOf(OverlayA)))
+    }
+
+    @Test
     fun snapToIdleIfClose_multipleTransitions() = runMonotonicClockTest {
         val state = MutableSceneTransitionLayoutStateImpl(SceneA, SceneTransitions.Empty)
 
@@ -601,4 +643,73 @@
             runBlocking { state.startTransition(transition) }
         }
     }
+
+    @Test
+    fun transitionFinishedWhenScopeIsEmpty() = runTest {
+        val state = MutableSceneTransitionLayoutState(SceneA)
+
+        // Start a transition.
+        val transition = transition(from = SceneA, to = SceneB)
+        state.startTransitionImmediately(backgroundScope, transition)
+        assertThat(state.transitionState).isSceneTransition()
+
+        // Start a job in the transition scope.
+        val jobCompletable = CompletableDeferred<Unit>()
+        transition.coroutineScope.launch { jobCompletable.await() }
+
+        // Finish the transition (i.e. make its #run() method return). The transition should not be
+        // considered as finished yet given that there is a job still running in its scope.
+        transition.finish()
+        runCurrent()
+        assertThat(state.transitionState).isSceneTransition()
+
+        // Finish the job in the scope. Now the transition should be considered as finished.
+        jobCompletable.complete(Unit)
+        runCurrent()
+        assertThat(state.transitionState).isIdle()
+    }
+
+    @Test
+    fun transitionScopeIsCancelledWhenTransitionIsForceFinished() = runTest {
+        val state = MutableSceneTransitionLayoutState(SceneA)
+
+        // Start a transition.
+        val transition = transition(from = SceneA, to = SceneB)
+        state.startTransitionImmediately(backgroundScope, transition)
+        assertThat(state.transitionState).isSceneTransition()
+
+        // Start a job in the transition scope that never finishes.
+        val job = transition.coroutineScope.launch { awaitCancellation() }
+
+        // Force snap state to SceneB to force finish all current transitions.
+        state.snapToScene(SceneB)
+        assertThat(state.transitionState).isIdle()
+        assertThat(job.isCancelled).isTrue()
+    }
+
+    @Test
+    fun badTransitionSpecThrowsMeaningfulMessageWhenStartingTransition() {
+        val state =
+            MutableSceneTransitionLayoutState(
+                SceneA,
+                transitions {
+                    // This transition definition is bad because they both match when transitioning
+                    // from A to B.
+                    from(SceneA) {}
+                    to(SceneB) {}
+                },
+            )
+
+        val exception =
+            assertThrows(IllegalStateException::class.java) {
+                runBlocking { state.startTransition(transition(from = SceneA, to = SceneB)) }
+            }
+
+        assertThat(exception)
+            .hasMessageThat()
+            .isEqualTo(
+                "Found multiple transition specs for transition SceneKey(debugName=SceneA) => " +
+                    "SceneKey(debugName=SceneB)"
+            )
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 97a96a4..b3a3261 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -55,7 +55,6 @@
 import androidx.compose.ui.test.swipeUp
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -672,12 +671,12 @@
         }
 
         assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
-        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1)
+        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1)
 
         // Move the pointer up to swipe to scene B using the new transition.
         rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
         assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
-        assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2)
+        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
     }
 
     @Test
@@ -685,7 +684,8 @@
         val swipeDistance =
             object : UserActionDistance {
                 override fun UserActionDistanceScope.absoluteDistance(
-                    fromSceneSize: IntSize,
+                    fromContent: ContentKey,
+                    toContent: ContentKey,
                     orientation: Orientation,
                 ): Float {
                     // Foo is going to have a vertical offset of 50dp. Let's make the swipe distance
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index d317114..70f2ff80 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -22,17 +22,23 @@
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.ui.unit.IntSize
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.TestScenes.SceneA
 import com.android.compose.animation.scene.TestScenes.SceneB
 import com.android.compose.animation.scene.TestScenes.SceneC
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
 import com.android.compose.animation.scene.transformation.OverscrollTranslate
+import com.android.compose.animation.scene.transformation.PropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import com.android.compose.animation.scene.transformation.TransformationMatcher
 import com.android.compose.animation.scene.transformation.TransformationRange
-import com.android.compose.animation.scene.transformation.TransformationWithRange
 import com.android.compose.test.transition
 import com.google.common.truth.Correspondence
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertThrows
 import org.junit.Test
@@ -98,7 +104,7 @@
         val transitions = transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations.size).isEqualTo(1)
         assertThat(transformations.single().range).isEqualTo(null)
     }
@@ -121,7 +127,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -152,7 +158,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -180,7 +186,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -210,7 +216,7 @@
         // to B we defined.
         val transitionSpec = transitions.transitionSpec(from = SceneB, to = SceneA, key = null)
 
-        val transformations = transitionSpec.transformationSpec(aToB()).transformations
+        val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers
 
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -220,7 +226,7 @@
             )
 
         val previewTransformations =
-            transitionSpec.previewTransformationSpec(aToB())?.transformations
+            transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
 
         assertThat(previewTransformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -250,7 +256,7 @@
                 key = TransitionKey.PredictiveBack,
             )
 
-        val transformations = transitionSpec.transformationSpec(aToB()).transformations
+        val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers
 
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -260,7 +266,7 @@
             )
 
         val previewTransformations =
-            transitionSpec.previewTransformationSpec(aToB())?.transformations
+            transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
 
         assertThat(previewTransformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -311,7 +317,7 @@
 
         val overscrollSpec = transitions.overscrollSpecs.single()
         val transformation =
-            overscrollSpec.transformationSpec.transformations.single().transformation
+            overscrollSpec.transformationSpec.transformationMatchers.single().factory.create()
         assertThat(transformation).isInstanceOf(OverscrollTranslate::class.java)
     }
 
@@ -319,7 +325,7 @@
     fun overscrollSpec_for_overscrollDisabled() {
         val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) }
         val overscrollSpec = transitions.overscrollSpecs.single()
-        assertThat(overscrollSpec.transformationSpec.transformations).isEmpty()
+        assertThat(overscrollSpec.transformationSpec.transformationMatchers).isEmpty()
     }
 
     @Test
@@ -343,9 +349,36 @@
         assertThat(transitionPassedToBuilder).isSameInstanceAs(transition)
     }
 
+    @Test
+    fun customTransitionsAreNotSupportedInRanges() = runTest {
+        val transitions = transitions {
+            from(SceneA, to = SceneB) {
+                fractionRange {
+                    transformation(TestElements.Foo) {
+                        object : CustomPropertyTransformation<IntSize> {
+                            override val property = PropertyTransformation.Property.Size
+
+                            override fun PropertyTransformationScope.transform(
+                                content: ContentKey,
+                                element: ElementKey,
+                                transition: TransitionState.Transition,
+                                transitionScope: CoroutineScope,
+                            ): IntSize = IntSize.Zero
+                        }
+                    }
+                }
+            }
+        }
+
+        val state = MutableSceneTransitionLayoutState(SceneA, transitions)
+        assertThrows(IllegalStateException::class.java) {
+            runBlocking { state.startTransition(transition(from = SceneA, to = SceneB)) }
+        }
+    }
+
     companion object {
         private val TRANSFORMATION_RANGE =
-            Correspondence.transforming<TransformationWithRange<*>, TransformationRange?>(
+            Correspondence.transforming<TransformationMatcher, TransformationRange?>(
                 { it?.range },
                 "has range equal to",
             )
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
index 313379f..0adb480 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt
@@ -157,7 +157,7 @@
         check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing)
     }
 
-    fun hasOverscrollSpec(): OverscrollSpec {
+    internal fun hasOverscrollSpec(): OverscrollSpec {
         check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull()
         return actual.currentOverscrollSpec!!
     }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt
new file mode 100644
index 0000000..444ec4e
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.test.assertSizeIsEqualTo
+import kotlinx.coroutines.CoroutineScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CustomTransformationTest {
+    @get:Rule val rule = createComposeRule()
+
+    @Test
+    fun customSize() {
+        /** A size transformation that adds [add] to the size of the transformed element(s). */
+        class AddSizeTransformation(private val add: Dp) : CustomPropertyTransformation<IntSize> {
+            override val property = PropertyTransformation.Property.Size
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): IntSize {
+                val idleSize = checkNotNull(element.targetSize(content))
+                val progress = 1f - transition.progressTo(content)
+                val addPx = (add * progress).roundToPx()
+                return IntSize(width = idleSize.width + addPx, height = idleSize.height + addPx)
+            }
+        }
+
+        rule.testTransition(
+            fromSceneContent = { Box(Modifier.element(TestElements.Foo).size(40.dp, 20.dp)) },
+            toSceneContent = {},
+            transition = {
+                spec = tween(16 * 4, easing = LinearEasing)
+
+                // Add 80dp to the width and height of Foo.
+                transformation(TestElements.Foo) { AddSizeTransformation(80.dp) }
+            },
+        ) {
+            before { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) }
+            at(0) { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) }
+            at(16) { onElement(TestElements.Foo).assertSizeIsEqualTo(60.dp, 40.dp) }
+            at(32) { onElement(TestElements.Foo).assertSizeIsEqualTo(80.dp, 60.dp) }
+            at(48) { onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 80.dp) }
+            after { onElement(TestElements.Foo).assertDoesNotExist() }
+        }
+    }
+
+    @Test
+    fun customOffset() {
+        /** An offset transformation that adds [add] to the offset of the transformed element(s). */
+        class AddOffsetTransformation(private val add: Dp) : CustomPropertyTransformation<Offset> {
+            override val property = PropertyTransformation.Property.Offset
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): Offset {
+                val idleOffset = checkNotNull(element.targetOffset(content))
+                val progress = 1f - transition.progressTo(content)
+                val addPx = (add * progress).toPx()
+                return Offset(x = idleOffset.x + addPx, y = idleOffset.y + addPx)
+            }
+        }
+
+        rule.testTransition(
+            fromSceneContent = { Box(Modifier.element(TestElements.Foo)) },
+            toSceneContent = {},
+            transition = {
+                spec = tween(16 * 4, easing = LinearEasing)
+
+                // Add 80dp to the offset of Foo.
+                transformation(TestElements.Foo) { AddOffsetTransformation(80.dp) }
+            },
+        ) {
+            before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) }
+            at(0) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) }
+            at(16) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(20.dp, 20.dp) }
+            at(32) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(40.dp, 40.dp) }
+            at(48) { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(60.dp, 60.dp) }
+            after { onElement(TestElements.Foo).assertDoesNotExist() }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 91079b8..28ea2d2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -53,7 +53,8 @@
         object : FlingBehavior {
             override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
                 scrollBy(initialVelocity)
-                return initialVelocity / 2f
+                // returns the remaining velocity: 1/3 remained + 2/3 consumed
+                return initialVelocity / 3f
             }
         }
 
@@ -207,11 +208,13 @@
 
         val consumed = scrollConnection.onPreFling(available = Velocity(2f, 2f))
 
-        assertThat(lastStop).isEqualTo(2f)
+        val initialVelocity = 2f
+        assertThat(lastStop).isEqualTo(initialVelocity)
         // flingToScroll should try to scroll the content, customFlingBehavior uses the velocity.
         assertThat(lastScroll).isEqualTo(2f)
-        // customFlingBehavior returns half of the vertical velocity.
-        assertThat(consumed).isEqualTo(Velocity(0f, 1f))
+        val remainingVelocity = initialVelocity / 3f
+        // customFlingBehavior returns 2/3 of the vertical velocity.
+        assertThat(consumed).isEqualTo(Velocity(0f, initialVelocity - remainingVelocity))
     }
 
     @Test
diff --git a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
index 651e401..18073ad 100644
--- a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml
@@ -16,4 +16,5 @@
 
 <resources>
     <dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+    <dimen name="status_view_margin_horizontal">8dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
index 10e630d..37cd590 100644
--- a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml
@@ -17,4 +17,5 @@
 <resources>
     <!-- For portrait direction in unfold foldable device, we don't need keyguard_smartspace_top_offset-->
     <dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+    <dimen name="status_view_margin_horizontal">62dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..c1cf42c
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="status_view_margin_horizontal">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml
new file mode 100644
index 0000000..54dbeaa
--- /dev/null
+++ b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="status_view_margin_horizontal">124dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml
index 7feea6e..041ae62 100644
--- a/packages/SystemUI/customization/res/values/dimens.xml
+++ b/packages/SystemUI/customization/res/values/dimens.xml
@@ -39,4 +39,5 @@
     <!--Dimens used in both lockscreen  preview and smartspace -->
     <dimen name="date_weather_view_height">24dp</dimen>
     <dimen name="enhanced_smartspace_height">104dp</dimen>
+    <dimen name="status_view_margin_horizontal">0dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt
deleted file mode 100644
index 2a2d333..0000000
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt
+++ /dev/null
@@ -1,252 +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.shared.clocks
-
-import android.content.Context
-import android.content.res.Resources
-import android.graphics.Typeface
-import android.graphics.drawable.Drawable
-import android.util.TypedValue
-import com.android.internal.policy.SystemBarUtils
-import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.monet.Style as MonetStyle
-import java.io.IOException
-
-class AssetLoader
-private constructor(
-    private val pluginCtx: Context,
-    private val sysuiCtx: Context,
-    private val baseDir: String,
-    var seedColor: Int?,
-    var overrideChroma: Float?,
-    val typefaceCache: TypefaceCache,
-    messageBuffer: MessageBuffer,
-) {
-    val logger = Logger(messageBuffer, TAG)
-    private val resources =
-        listOf(
-            Pair(pluginCtx.resources, pluginCtx.packageName),
-            Pair(sysuiCtx.resources, sysuiCtx.packageName),
-        )
-
-    constructor(
-        pluginCtx: Context,
-        sysuiCtx: Context,
-        baseDir: String,
-        messageBuffer: MessageBuffer,
-    ) : this(
-        pluginCtx,
-        sysuiCtx,
-        baseDir,
-        seedColor = null,
-        overrideChroma = null,
-        typefaceCache =
-            TypefaceCache(messageBuffer) {
-                // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
-                return@TypefaceCache Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
-            },
-        messageBuffer = messageBuffer,
-    )
-
-    fun listAssets(path: String): List<String> {
-        return pluginCtx.resources.assets.list("$baseDir$path")?.toList() ?: emptyList()
-    }
-
-    fun tryReadString(resStr: String): String? = tryRead(resStr, ::readString)
-
-    fun readString(resStr: String): String {
-        val resPair = resolveResourceId(resStr)
-        if (resPair == null) {
-            throw IOException("Failed to parse string: $resStr")
-        }
-
-        val (res, id) = resPair
-        return res.getString(id)
-    }
-
-    fun readFontAsset(resStr: String): Typeface = typefaceCache.getTypeface(resStr)
-
-    fun tryReadTextAsset(path: String?): String? = tryRead(path, ::readTextAsset)
-
-    fun readTextAsset(path: String): String {
-        return pluginCtx.resources.assets.open("$baseDir$path").use { stream ->
-            val buffer = ByteArray(stream.available())
-            stream.read(buffer)
-            String(buffer)
-        }
-    }
-
-    fun tryReadDrawableAsset(path: String?): Drawable? = tryRead(path, ::readDrawableAsset)
-
-    fun readDrawableAsset(path: String): Drawable {
-        var result: Drawable?
-
-        if (path.startsWith("@")) {
-            val pair = resolveResourceId(path)
-            if (pair == null) {
-                throw IOException("Failed to parse $path to an id")
-            }
-            val (res, id) = pair
-            result = res.getDrawable(id)
-        } else if (path.endsWith("xml")) {
-            // TODO(b/248609434): Support xml files in assets
-            throw IOException("Cannot load xml files from assets")
-        } else {
-            // Attempt to load as if it's a bitmap and directly loadable
-            result =
-                pluginCtx.resources.assets.open("$baseDir$path").use { stream ->
-                    Drawable.createFromResourceStream(
-                        pluginCtx.resources,
-                        TypedValue(),
-                        stream,
-                        null,
-                    )
-                }
-        }
-
-        return result ?: throw IOException("Failed to load: $baseDir$path")
-    }
-
-    fun parseResourceId(resStr: String): Triple<String?, String, String> {
-        if (!resStr.startsWith("@")) {
-            throw IOException("Invalid resource id: $resStr; Must start with '@'")
-        }
-
-        // Parse out resource string
-        val parts = resStr.drop(1).split('/', ':')
-        return when (parts.size) {
-            2 -> Triple(null, parts[0], parts[1])
-            3 -> Triple(parts[0], parts[1], parts[2])
-            else -> throw IOException("Failed to parse resource string: $resStr")
-        }
-    }
-
-    fun resolveResourceId(resStr: String): Pair<Resources, Int>? {
-        val (packageName, category, name) = parseResourceId(resStr)
-        return resolveResourceId(packageName, category, name)
-    }
-
-    fun resolveResourceId(
-        packageName: String?,
-        category: String,
-        name: String,
-    ): Pair<Resources, Int>? {
-        for ((res, ctxPkgName) in resources) {
-            val result = res.getIdentifier(name, category, packageName ?: ctxPkgName)
-            if (result != 0) {
-                return Pair(res, result)
-            }
-        }
-        return null
-    }
-
-    private fun <TArg : Any, TRes : Any> tryRead(arg: TArg?, fn: (TArg) -> TRes): TRes? {
-        try {
-            if (arg == null) {
-                return null
-            }
-            return fn(arg)
-        } catch (ex: IOException) {
-            logger.w("Failed to read $arg", ex)
-            return null
-        }
-    }
-
-    fun assetExists(path: String): Boolean {
-        try {
-            if (path.startsWith("@")) {
-                val pair = resolveResourceId(path)
-                return pair != null
-            } else {
-                val stream = pluginCtx.resources.assets.open("$baseDir$path")
-                if (stream == null) {
-                    return false
-                }
-
-                stream.close()
-                return true
-            }
-        } catch (ex: IOException) {
-            return false
-        }
-    }
-
-    fun copy(messageBuffer: MessageBuffer? = null): AssetLoader =
-        AssetLoader(
-            pluginCtx,
-            sysuiCtx,
-            baseDir,
-            seedColor,
-            overrideChroma,
-            typefaceCache,
-            messageBuffer ?: logger.buffer,
-        )
-
-    fun setSeedColor(seedColor: Int?, style: MonetStyle?) {
-        this.seedColor = seedColor
-    }
-
-    fun getClockPaddingStart(): Int {
-        val result = resolveResourceId(null, "dimen", "clock_padding_start")
-        if (result != null) {
-            val (res, id) = result
-            return res.getDimensionPixelSize(id)
-        }
-        return -1
-    }
-
-    fun getStatusBarHeight(): Int {
-        val display = pluginCtx.getDisplayNoVerify()
-        if (display != null) {
-            return SystemBarUtils.getStatusBarHeight(pluginCtx.resources, display.cutout)
-        }
-
-        logger.w("No display available; falling back to android.R.dimen.status_bar_height")
-        val statusBarHeight = resolveResourceId("android", "dimen", "status_bar_height")
-        if (statusBarHeight != null) {
-            val (res, resId) = statusBarHeight
-            return res.getDimensionPixelSize(resId)
-        }
-
-        throw Exception("Could not fetch StatusBarHeight")
-    }
-
-    fun getResourcesId(name: String): Int = getResource("id", name) { _, id -> id }
-
-    fun getDimen(name: String): Int = getResource("dimen", name, Resources::getDimensionPixelSize)
-
-    fun getString(name: String): String = getResource("string", name, Resources::getString)
-
-    private fun <T> getResource(
-        category: String,
-        name: String,
-        getter: (res: Resources, id: Int) -> T,
-    ): T {
-        val result = resolveResourceId(null, category, name)
-        if (result != null) {
-            val (res, id) = result
-            if (id == -1) throw Exception("Cannot find id of $id from $TAG")
-            return getter(res, id)
-        }
-        throw Exception("Cannot find id of $name from $TAG")
-    }
-
-    companion object {
-        private val TAG = AssetLoader::class.simpleName!!
-    }
-}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
index 4ed8fd8..d0a32dc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt
@@ -16,12 +16,9 @@
 
 package com.android.systemui.shared.clocks
 
-import android.content.Context
-import android.content.res.Resources
 import android.graphics.Rect
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockEvents
@@ -37,31 +34,22 @@
 import java.util.TimeZone
 
 class ComposedDigitalLayerController(
-    private val ctx: Context,
-    private val resources: Resources,
-    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    private val clockCtx: ClockContext,
     private val layer: ComposedDigitalHandLayer,
-    messageBuffer: MessageBuffer,
 ) : SimpleClockLayerController {
-    private val logger = Logger(messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
+    private val logger =
+        Logger(clockCtx.messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
 
     val layerControllers = mutableListOf<SimpleClockLayerController>()
     val dozeState = DefaultClockController.AnimationState(1F)
 
-    override val view = FlexClockView(ctx, assets, messageBuffer)
+    override val view = FlexClockView(clockCtx)
 
     init {
         layer.digitalLayers.forEach {
-            val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
+            val childView = SimpleDigitalClockTextView(clockCtx)
             val controller =
-                SimpleDigitalHandLayerController(
-                    ctx,
-                    resources,
-                    assets,
-                    it as DigitalHandLayer,
-                    childView,
-                    messageBuffer,
-                )
+                SimpleDigitalHandLayerController(clockCtx, it as DigitalHandLayer, childView)
 
             view.addView(childView)
             layerControllers.add(controller)
@@ -156,8 +144,9 @@
                 val color =
                     when {
                         theme.seedColor != null -> theme.seedColor!!
-                        theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100)
-                        else -> resources.getColor(android.R.color.system_accent2_600)
+                        theme.isDarkTheme ->
+                            clockCtx.resources.getColor(android.R.color.system_accent1_100)
+                        else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
                     }
 
                 view.updateColor(color)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index be4ebdf..9bb92bc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -15,10 +15,10 @@
 
 import android.content.Context
 import android.content.res.Resources
+import android.graphics.Typeface
 import android.view.LayoutInflater
 import com.android.systemui.customization.R
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.core.LogcatOnlyMessageBuffer
+import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFontAxis
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
@@ -33,6 +33,15 @@
 private val TAG = DefaultClockProvider::class.simpleName
 const val DEFAULT_CLOCK_ID = "DEFAULT"
 
+data class ClockContext(
+    val context: Context,
+    val resources: Resources,
+    val settings: ClockSettings,
+    val typefaceCache: TypefaceCache,
+    val messageBuffers: ClockMessageBuffers,
+    val messageBuffer: MessageBuffer,
+)
+
 /** Provides the default system clock */
 class DefaultClockProvider(
     val ctx: Context,
@@ -55,18 +64,20 @@
         }
 
         return if (isClockReactiveVariantsEnabled) {
-            val buffer =
-                messageBuffers?.infraMessageBuffer ?: LogcatOnlyMessageBuffer(LogLevel.INFO)
-            val assets = AssetLoader(ctx, ctx, "clocks/", buffer)
-            assets.setSeedColor(settings.seedColor, null)
+            val buffers = messageBuffers ?: ClockMessageBuffers(LogUtil.DEFAULT_MESSAGE_BUFFER)
             val fontAxes = ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes)
+            val clockSettings = settings.copy(axes = fontAxes.map { it.toSetting() })
+            val typefaceCache = TypefaceCache(buffers.infraMessageBuffer) { FLEX_TYPEFACE }
             FlexClockController(
-                ctx,
-                resources,
-                settings.copy(axes = fontAxes.map { it.toSetting() }),
-                assets,
+                ClockContext(
+                    ctx,
+                    resources,
+                    clockSettings,
+                    typefaceCache,
+                    buffers,
+                    buffers.infraMessageBuffer,
+                ),
                 FLEX_DESIGN,
-                messageBuffers,
             )
         } else {
             DefaultClockController(
@@ -116,6 +127,11 @@
                 ClockFontAxisSetting("slnt", 0f),
             )
 
+        val FLEX_TYPEFACE by lazy {
+            // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
+            Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
+        }
+
         val FLEX_DESIGN = run {
             val largeLayer =
                 listOf(
@@ -139,7 +155,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "hh",
                                 ),
@@ -158,7 +174,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "hh",
                                 ),
@@ -177,7 +193,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "mm",
                                 ),
@@ -196,7 +212,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "mm",
                                 ),
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 6c627e2..c7a3f63 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.shared.clocks
 
-import android.content.Context
-import android.content.res.Resources
 import com.android.systemui.customization.R
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.AxisType
@@ -26,8 +24,6 @@
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFontAxis
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.plugins.clocks.ClockMessageBuffers
-import com.android.systemui.plugins.clocks.ClockSettings
 import com.android.systemui.plugins.clocks.ThemeConfig
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
@@ -38,42 +34,28 @@
 
 /** Controller for the default flex clock */
 class FlexClockController(
-    private val ctx: Context,
-    private val resources: Resources,
-    private val settings: ClockSettings,
-    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    private val clockCtx: ClockContext,
     val design: ClockDesign, // TODO(b/364680879): Remove when done inlining
-    val messageBuffers: ClockMessageBuffers?,
 ) : ClockController {
-    override val smallClock = run {
-        val buffer = messageBuffers?.smallClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+    override val smallClock =
         FlexClockFaceController(
-            ctx,
-            resources,
-            assets.copy(messageBuffer = buffer),
+            clockCtx.copy(messageBuffer = clockCtx.messageBuffers.smallClockMessageBuffer),
             design.small ?: design.large!!,
-            false,
-            buffer,
+            isLargeClock = false,
         )
-    }
 
-    override val largeClock = run {
-        val buffer = messageBuffers?.largeClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER
+    override val largeClock =
         FlexClockFaceController(
-            ctx,
-            resources,
-            assets.copy(messageBuffer = buffer),
+            clockCtx.copy(messageBuffer = clockCtx.messageBuffers.largeClockMessageBuffer),
             design.large ?: design.small!!,
-            true,
-            buffer,
+            isLargeClock = true,
         )
-    }
 
     override val config: ClockConfig by lazy {
         ClockConfig(
             DEFAULT_CLOCK_ID,
-            resources.getString(R.string.clock_default_name),
-            resources.getString(R.string.clock_default_description),
+            clockCtx.resources.getString(R.string.clock_default_name),
+            clockCtx.resources.getString(R.string.clock_default_description),
             isReactiveToTone = true,
         )
     }
@@ -125,8 +107,8 @@
         }
 
     override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) {
-        val theme = ThemeConfig(isDarkTheme, assets.seedColor)
-        events.onFontAxesChanged(settings.axes)
+        val theme = ThemeConfig(isDarkTheme, clockCtx.settings.seedColor)
+        events.onFontAxesChanged(clockCtx.settings.axes)
 
         smallClock.run {
             events.onThemeChanged(theme)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
index ee21ea6..a8890e6 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt
@@ -16,15 +16,12 @@
 
 package com.android.systemui.shared.clocks
 
-import android.content.Context
-import android.content.res.Resources
 import android.graphics.Rect
 import android.view.Gravity
 import android.view.View
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.FrameLayout
 import com.android.systemui.customization.R
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockEvents
@@ -45,22 +42,19 @@
 
 // TODO(b/364680879): Merge w/ ComposedDigitalLayerController
 class FlexClockFaceController(
-    ctx: Context,
-    private val resources: Resources,
-    val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    clockCtx: ClockContext,
     face: ClockFace,
     private val isLargeClock: Boolean,
-    messageBuffer: MessageBuffer,
 ) : ClockFaceController {
     override val view: View
         get() = layerController.view
 
     override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true)
 
-    override var theme = ThemeConfig(true, assets.seedColor)
+    override var theme = ThemeConfig(true, clockCtx.settings.seedColor)
 
     private val keyguardLargeClockTopMargin =
-        resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
+        clockCtx.resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
     val layerController: SimpleClockLayerController
     val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm")
 
@@ -72,23 +66,10 @@
 
         layerController =
             if (isLargeClock) {
-                ComposedDigitalLayerController(
-                    ctx,
-                    resources,
-                    assets,
-                    layer as ComposedDigitalHandLayer,
-                    messageBuffer,
-                )
+                ComposedDigitalLayerController(clockCtx, layer as ComposedDigitalHandLayer)
             } else {
-                val childView = SimpleDigitalClockTextView(ctx, messageBuffer)
-                SimpleDigitalHandLayerController(
-                    ctx,
-                    resources,
-                    assets,
-                    layer as DigitalHandLayer,
-                    childView,
-                    messageBuffer,
-                )
+                val childView = SimpleDigitalClockTextView(clockCtx)
+                SimpleDigitalHandLayerController(clockCtx, layer as DigitalHandLayer, childView)
             }
         layerController.view.layoutParams = lp
     }
@@ -97,7 +78,7 @@
     private fun offsetGlyphsForStepClockAnimation(
         clockStartLeft: Int,
         direction: Int,
-        fraction: Float
+        fraction: Float,
     ) {
         (view as? FlexClockView)?.offsetGlyphsForStepClockAnimation(
             clockStartLeft,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
index 143b28f..ebac4b24 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.shared.clocks
 
-import android.content.Context
-import android.content.res.Resources
 import android.graphics.Rect
 import android.view.View
 import android.view.ViewGroup
@@ -25,7 +23,6 @@
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.customization.R
 import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockEvents
@@ -42,14 +39,11 @@
 private val TAG = SimpleDigitalHandLayerController::class.simpleName!!
 
 open class SimpleDigitalHandLayerController<T>(
-    private val ctx: Context,
-    private val resources: Resources,
-    private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
+    private val clockCtx: ClockContext,
     private val layer: DigitalHandLayer,
     override val view: T,
-    messageBuffer: MessageBuffer,
 ) : SimpleClockLayerController where T : View, T : SimpleDigitalClockView {
-    private val logger = Logger(messageBuffer, TAG)
+    private val logger = Logger(clockCtx.messageBuffer, TAG)
     val timespec = DigitalTimespecHandler(layer.timespec, layer.dateTimeFormat)
 
     @VisibleForTesting
@@ -75,12 +69,12 @@
             layer.alignment.verticalAlignment?.let { view.verticalAlignment = it }
             layer.alignment.horizontalAlignment?.let { view.horizontalAlignment = it }
         }
-        view.applyStyles(assets, layer.style, layer.aodStyle)
+        view.applyStyles(layer.style, layer.aodStyle)
         view.id =
-            ctx.resources.getIdentifier(
+            clockCtx.resources.getIdentifier(
                 generateDigitalLayerIdString(layer),
                 "id",
-                ctx.getPackageName(),
+                clockCtx.context.getPackageName(),
             )
     }
 
@@ -306,8 +300,9 @@
                 val color =
                     when {
                         theme.seedColor != null -> theme.seedColor!!
-                        theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100)
-                        else -> resources.getColor(android.R.color.system_accent2_600)
+                        theme.isDarkTheme ->
+                            clockCtx.resources.getColor(android.R.color.system_accent1_100)
+                        else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
                     }
 
                 view.updateColor(color)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
index b09332f..d4eb767 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt
@@ -16,24 +16,23 @@
 
 package com.android.systemui.shared.clocks.view
 
-import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Point
 import android.view.View
 import android.widget.FrameLayout
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
+import com.android.systemui.shared.clocks.ClockContext
 import com.android.systemui.shared.clocks.LogUtil
 import java.util.Locale
 
 // TODO(b/364680879): Merge w/ only subclass FlexClockView
-abstract class DigitalClockFaceView(ctx: Context, messageBuffer: MessageBuffer) : FrameLayout(ctx) {
-    protected val logger = Logger(messageBuffer, this::class.simpleName!!)
+abstract class DigitalClockFaceView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) {
+    protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!)
         get() = field ?: LogUtil.FALLBACK_INIT_LOGGER
 
     abstract var digitalClockTextViewMap: MutableMap<Int, SimpleDigitalClockTextView>
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index 593eba9..faef18c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -16,31 +16,34 @@
 
 package com.android.systemui.shared.clocks.view
 
-import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Point
+import android.icu.text.NumberFormat
 import android.util.MathUtils.constrainedMap
 import android.view.View
 import android.view.ViewGroup
 import android.widget.RelativeLayout
 import com.android.app.animation.Interpolators
 import com.android.systemui.customization.R
-import com.android.systemui.log.core.MessageBuffer
-import com.android.systemui.shared.clocks.AssetLoader
+import com.android.systemui.shared.clocks.ClockContext
 import com.android.systemui.shared.clocks.DigitTranslateAnimator
+import java.util.Locale
 import kotlin.math.abs
 import kotlin.math.max
 import kotlin.math.min
 
 fun clamp(value: Float, minVal: Float, maxVal: Float): Float = max(min(value, maxVal), minVal)
 
-class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: MessageBuffer) :
-    DigitalClockFaceView(context, messageBuffer) {
+class FlexClockView(clockCtx: ClockContext) : DigitalClockFaceView(clockCtx) {
     override var digitalClockTextViewMap = mutableMapOf<Int, SimpleDigitalClockTextView>()
-    val digitLeftTopMap = mutableMapOf<Int, Point>()
-    var maxSingleDigitSize = Point(-1, -1)
-    val lockscreenTranslate = Point(0, 0)
-    var aodTranslate = Point(0, 0)
+    private val digitLeftTopMap = mutableMapOf<Int, Point>()
+
+    private var maxSingleDigitSize = Point(-1, -1)
+    private val lockscreenTranslate = Point(0, 0)
+    private var aodTranslate = Point(0, 0)
+
+    // Does the current language have mono vertical size when displaying numerals
+    private var isMonoVerticalNumericLineSpacing = true
 
     init {
         setWillNotDraw(false)
@@ -49,6 +52,7 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
             )
+        updateLocale(Locale.getDefault())
     }
 
     private val digitOffsets = mutableMapOf<Int, Float>()
@@ -61,12 +65,19 @@
 
     protected override fun calculateSize(widthMeasureSpec: Int, heightMeasureSpec: Int): Point {
         maxSingleDigitSize = Point(-1, -1)
+        val bottomLocation: (textView: SimpleDigitalClockTextView) -> Int = { textView ->
+            if (isMonoVerticalNumericLineSpacing) {
+                maxSingleDigitSize.y
+            } else {
+                (textView.paint.fontMetrics.descent - textView.paint.fontMetrics.ascent).toInt()
+            }
+        }
+
         digitalClockTextViewMap.forEach { (_, textView) ->
             textView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
             maxSingleDigitSize.x = max(maxSingleDigitSize.x, textView.measuredWidth)
-            maxSingleDigitSize.y = max(maxSingleDigitSize.y, textView.measuredHeight)
+            maxSingleDigitSize.y = max(bottomLocation(textView), textView.measuredHeight)
         }
-        val textView = digitalClockTextViewMap[R.id.HOUR_FIRST_DIGIT]!!
         aodTranslate = Point(0, 0)
         return Point(
             ((maxSingleDigitSize.x + abs(aodTranslate.x)) * 2),
@@ -106,6 +117,11 @@
         }
     }
 
+    override fun onLocaleChanged(locale: Locale) {
+        updateLocale(locale)
+        requestLayout()
+    }
+
     override fun animateDoze(isDozing: Boolean, isAnimated: Boolean) {
         dozeControlState.animateDoze = {
             super.animateDoze(isDozing, isAnimated)
@@ -166,6 +182,18 @@
         }
     }
 
+    private fun updateLocale(locale: Locale) {
+        isMonoVerticalNumericLineSpacing =
+            !NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES.any {
+                val newLocaleNumberFormat =
+                    NumberFormat.getInstance(locale).format(FORMAT_NUMBER.toLong())
+                val nonMonoVerticalNumericLineSpaceNumberFormat =
+                    NumberFormat.getInstance(Locale.forLanguageTag(it))
+                        .format(FORMAT_NUMBER.toLong())
+                newLocaleNumberFormat == nonMonoVerticalNumericLineSpaceNumberFormat
+            }
+    }
+
     /**
      * Offsets the textViews of the clock for the step clock animation.
      *
@@ -264,10 +292,18 @@
         // Constants for the animation
         private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED
 
+        private const val FORMAT_NUMBER = 1234567890
+
         // Total available transition time for each digit, taking into account the step. If step is
         // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7.
         private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1)
 
+        // Add language tags below that do not have vertically mono spaced numerals
+        private val NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES =
+            setOf(
+                "my", // Burmese
+            )
+
         // Use the sign of targetTranslation to control the direction of digit translation
         fun updateDirectionalTargetTranslate(id: Int, targetTranslation: Point): Point {
             val outPoint = Point(targetTranslation)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 5c84f2d..48761c0 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.shared.clocks.view
 
 import android.annotation.SuppressLint
-import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Paint
@@ -37,13 +36,11 @@
 import android.widget.TextView
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.animation.TextAnimator
-import com.android.systemui.animation.TypefaceVariantCache
 import com.android.systemui.customization.R
 import com.android.systemui.log.core.Logger
-import com.android.systemui.log.core.MessageBuffer
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.shared.clocks.AssetLoader
 import com.android.systemui.shared.clocks.ClockAnimation
+import com.android.systemui.shared.clocks.ClockContext
 import com.android.systemui.shared.clocks.DigitTranslateAnimator
 import com.android.systemui.shared.clocks.DimensionParser
 import com.android.systemui.shared.clocks.FontTextStyle
@@ -57,18 +54,15 @@
 private val TAG = SimpleDigitalClockTextView::class.simpleName!!
 
 @SuppressLint("AppCompatCustomView")
-open class SimpleDigitalClockTextView(
-    ctx: Context,
-    messageBuffer: MessageBuffer,
-    attrs: AttributeSet? = null,
-) : TextView(ctx, attrs), SimpleDigitalClockView {
+open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSet? = null) :
+    TextView(clockCtx.context, attrs), SimpleDigitalClockView {
     val lockScreenPaint = TextPaint()
     override lateinit var textStyle: FontTextStyle
     lateinit var aodStyle: FontTextStyle
 
     private var lsFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_LS_VARIATION)
     private var aodFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_AOD_VARIATION)
-    private val parser = DimensionParser(ctx)
+    private val parser = DimensionParser(clockCtx.context)
     var maxSingleDigitHeight = -1
     var maxSingleDigitWidth = -1
     var digitTranslateAnimator: DigitTranslateAnimator? = null
@@ -91,33 +85,23 @@
     private val prevTextBounds = Rect()
     // targetTextBounds holds the state we are interpolating to
     private val targetTextBounds = Rect()
-    protected val logger = Logger(messageBuffer, this::class.simpleName!!)
+    protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!)
         get() = field ?: LogUtil.FALLBACK_INIT_LOGGER
 
     private var aodDozingInterpolator: Interpolator? = null
 
     @VisibleForTesting lateinit var textAnimator: TextAnimator
 
-    lateinit var typefaceCache: TypefaceVariantCache
-        private set
-
-    private fun setTypefaceCache(value: TypefaceVariantCache) {
-        typefaceCache = value
-        if (this::textAnimator.isInitialized) {
-            textAnimator.typefaceCache = value
-        }
-    }
+    private val typefaceCache = clockCtx.typefaceCache.getVariantCache("")
 
     @VisibleForTesting
     var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb ->
         TextAnimator(layout, ClockAnimation.NUM_CLOCK_FONT_ANIMATION_STEPS, invalidateCb).also {
-            if (this::typefaceCache.isInitialized) {
-                it.typefaceCache = typefaceCache
-            }
+            it.typefaceCache = typefaceCache
         }
     }
 
-    override var verticalAlignment: VerticalAlignment = VerticalAlignment.CENTER
+    override var verticalAlignment: VerticalAlignment = VerticalAlignment.BASELINE
     override var horizontalAlignment: HorizontalAlignment = HorizontalAlignment.LEFT
     override var isAnimationEnabled = true
     override var dozeFraction: Float = 0F
@@ -258,7 +242,7 @@
                 -translation.y.toFloat(),
                 (-translation.x + measuredWidth).toFloat(),
                 (-translation.y + measuredHeight).toFloat(),
-                Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) },
+                PORTER_DUFF_XFER_MODE_PAINT,
             )
             canvas.restore()
             canvas.restore()
@@ -403,7 +387,7 @@
 
     // translation of reference point of text
     // used for translation when calling textInterpolator
-    fun getLocalTranslation(): Point {
+    private fun getLocalTranslation(): Point {
         val viewHeight = if (isVertical) measuredWidth else measuredHeight
         val interpolatedTextBounds = updateInterpolatedTextBounds()
         val localTranslation = Point(0, 0)
@@ -429,17 +413,18 @@
                         correctedBaseline
             }
             VerticalAlignment.BASELINE -> {
-                localTranslation.y = -lockScreenPaint.strokeWidth.toInt()
+                // account for max bottom distance of font, so clock doesn't collide with elements
+                localTranslation.y =
+                    -lockScreenPaint.strokeWidth.toInt() - paint.fontMetrics.descent.toInt()
             }
         }
 
         return updateXtranslation(localTranslation, interpolatedTextBounds)
     }
 
-    override fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?) {
+    override fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?) {
         this.textStyle = textStyle as FontTextStyle
         val typefaceName = "fonts/" + textStyle.fontFamily
-        setTypefaceCache(assets.typefaceCache.getVariantCache(typefaceName))
         lockScreenPaint.strokeJoin = Paint.Join.ROUND
         lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
         textStyle.fontFeatureSettings?.let {
@@ -550,7 +535,9 @@
     }
 
     companion object {
-        val AOD_STROKE_WIDTH = "2dp"
+        private val PORTER_DUFF_XFER_MODE_PAINT =
+            Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) }
+
         val AOD_COLOR = Color.WHITE
         val OPTICAL_SIZE_AXIS = ClockFontAxisSetting("opsz", 144f)
         val DEFAULT_LS_VARIATION =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
index 3d2ed4a1..e8be28f 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt
@@ -18,7 +18,6 @@
 
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
-import com.android.systemui.shared.clocks.AssetLoader
 import com.android.systemui.shared.clocks.TextStyle
 
 interface SimpleDigitalClockView {
@@ -29,7 +28,7 @@
     val textStyle: TextStyle
     @VisibleForTesting var isAnimationEnabled: Boolean
 
-    fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?)
+    fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?)
 
     fun applyTextSize(targetFontSizePx: Float?, constrainedByHeight: Boolean = false)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
index 57a6797..85bdf92 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt
@@ -28,7 +28,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.settings.FakeDisplayTracker
-import com.android.systemui.shade.data.repository.FakeShadePositionRepository
+import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import java.util.concurrent.Executor
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -62,7 +62,7 @@
         mock(ConnectedDisplayKeyguardPresentation::class.java)
     @Mock private val deviceStateHelper = mock(DeviceStateHelper::class.java)
     @Mock private val keyguardStateController = mock(KeyguardStateController::class.java)
-    private val shadePositionRepository = FakeShadePositionRepository()
+    private val shadePositionRepository = FakeShadeDisplayRepository()
 
     private val mainExecutor = Executor { it.run() }
     private val backgroundExecutor = Executor { it.run() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/BatteryMeterDrawableTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/BatteryMeterDrawableTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/BootCompleteCacheTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/BootCompleteCacheTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FakeCameraProtectionLoader.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/FakeCameraProtectionLoader.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/FakeCameraProtectionLoader.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/FakeCameraProtectionLoader.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index fcb433b..9d471f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -45,9 +45,9 @@
 import android.platform.test.annotations.EnableFlags;
 import android.provider.Settings;
 import android.testing.TestableLooper;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 import android.widget.Space;
 import android.widget.Spinner;
 
@@ -166,6 +166,7 @@
         when(mCachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
         when(mCachedDevice.isConnectedHearingAidDevice()).thenReturn(true);
         when(mCachedDevice.isConnectedHapClientDevice()).thenReturn(true);
+        when(mCachedDevice.getDrawableWithDescription()).thenReturn(new Pair<>(mDrawable, ""));
         when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice);
 
         mContext.setMockPackageManager(mPackageManager);
@@ -217,6 +218,18 @@
 
     @Test
     @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
+    public void showDialog_noLiveCaption_noRelatedToolsInConfig_relatedToolLayoutGone() {
+        mContext.getOrCreateTestableResources().addOverride(
+                R.array.config_quickSettingsHearingDevicesRelatedToolName, new String[]{});
+
+        setUpPairNewDeviceDialog();
+        mDialog.show();
+
+        assertToolsUi(0);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS)
     public void showDialog_hasLiveCaption_noRelatedToolsInConfig_showOneRelatedTool() {
         when(mPackageManager.queryIntentActivities(
                 eq(LIVE_CAPTION_INTENT), anyInt())).thenReturn(
@@ -227,8 +240,7 @@
         setUpPairNewDeviceDialog();
         mDialog.show();
 
-        LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog);
-        assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(1);
+        assertToolsUi(1);
     }
 
     @Test
@@ -251,8 +263,7 @@
         setUpPairNewDeviceDialog();
         mDialog.show();
 
-        LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog);
-        assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(2);
+        assertToolsUi(2);
     }
 
     @Test
@@ -263,8 +274,8 @@
         setUpDeviceListDialog();
         mDialog.show();
 
-        Spinner spinner = (Spinner) getPresetSpinner(mDialog);
-        assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
+        ViewGroup presetLayout = getPresetLayout(mDialog);
+        assertThat(presetLayout.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
@@ -276,8 +287,9 @@
         setUpDeviceListDialog();
         mDialog.show();
 
-        Spinner spinner = (Spinner) getPresetSpinner(mDialog);
-        assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+        ViewGroup presetLayout = getPresetLayout(mDialog);
+        assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
+        Spinner spinner = getPresetSpinner(mDialog);
         assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
     }
 
@@ -292,8 +304,9 @@
         mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO);
         mTestableLooper.processAllMessages();
 
-        Spinner spinner = (Spinner) getPresetSpinner(mDialog);
-        assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+        ViewGroup presetLayout = getPresetLayout(mDialog);
+        assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE);
+        Spinner spinner = getPresetSpinner(mDialog);
         assertThat(spinner.getSelectedItemPosition()).isEqualTo(0);
     }
 
@@ -359,14 +372,23 @@
         return dialog.requireViewById(R.id.pair_new_device_button);
     }
 
-    private View getRelatedToolsView(SystemUIDialog dialog) {
-        return dialog.requireViewById(R.id.related_tools_container);
+    private ViewGroup getToolsContainer(SystemUIDialog dialog) {
+        return dialog.requireViewById(R.id.tools_container);
     }
 
-    private View getPresetSpinner(SystemUIDialog dialog) {
+    private ViewGroup getToolsLayout(SystemUIDialog dialog) {
+        return dialog.requireViewById(R.id.tools_layout);
+    }
+
+    private Spinner getPresetSpinner(SystemUIDialog dialog) {
         return dialog.requireViewById(R.id.preset_spinner);
     }
 
+    private ViewGroup getPresetLayout(SystemUIDialog dialog) {
+        return dialog.requireViewById(R.id.preset_layout);
+    }
+
+
     private int countChildWithoutSpace(ViewGroup viewGroup) {
         int spaceCount = 0;
         for (int i = 0; i < viewGroup.getChildCount(); i++) {
@@ -377,6 +399,15 @@
         return viewGroup.getChildCount() - spaceCount;
     }
 
+    private void assertToolsUi(int childCount) {
+        ViewGroup toolsContainer = getToolsContainer(mDialog);
+        assertThat(countChildWithoutSpace(toolsContainer)).isEqualTo(childCount);
+
+        int targetVisibility = childCount == 0 ? View.GONE : View.VISIBLE;
+        ViewGroup toolsLayout = getToolsLayout(mDialog);
+        assertThat(toolsLayout.getVisibility()).isEqualTo(targetVisibility);
+    }
+
     @After
     public void reset() {
         if (mDialogDelegate != null) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index 72163e4..f82c8b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -31,7 +31,8 @@
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.util.mockito.whenever
@@ -62,7 +63,7 @@
     private val testScope = kosmos.testScope
     private val clock = FakeSystemClock()
     private val userRepository = FakeUserRepository()
-    private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+    private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository
 
     private lateinit var underTest: AuthenticationRepository
 
@@ -110,7 +111,7 @@
                 .isEqualTo(AuthenticationMethodModel.None)
 
             currentSecurityMode = KeyguardSecurityModel.SecurityMode.SimPin
-            mobileConnectionsRepository.isAnySimSecure.value = true
+            mobileConnectionsRepository.fake.isAnySimSecure.value = true
             assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Sim)
             assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Sim)
         }
@@ -199,7 +200,7 @@
         }
 
     private fun setSecurityModeAndDispatchBroadcast(
-        securityMode: KeyguardSecurityModel.SecurityMode,
+        securityMode: KeyguardSecurityModel.SecurityMode
     ) {
         currentSecurityMode = securityMode
         dispatchBroadcast()
@@ -208,23 +209,15 @@
     private fun dispatchBroadcast() {
         fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
             context,
-            Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED)
+            Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
         )
     }
 
     companion object {
         private val USER_INFOS =
             listOf(
-                UserInfo(
-                    /* id= */ 100,
-                    /* name= */ "First user",
-                    /* flags= */ 0,
-                ),
-                UserInfo(
-                    /* id= */ 101,
-                    /* name= */ "Second user",
-                    /* flags= */ 0,
-                ),
+                UserInfo(/* id= */ 100, /* name= */ "First user", /* flags= */ 0),
+                UserInfo(/* id= */ 101, /* name= */ "Second user", /* flags= */ 0),
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
index beb816c..32606e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDialogViewModelTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.bluetooth.qsdialog
 
 import android.bluetooth.BluetoothDevice
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.bluetooth.LeAudioProfile
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
@@ -48,7 +48,7 @@
 import org.mockito.kotlin.whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @OptIn(ExperimentalCoroutinesApi::class)
 class AudioSharingDialogViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
index c9e8813..acfe9dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
@@ -17,8 +17,8 @@
 
 import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothLeBroadcastMetadata
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
@@ -46,7 +46,7 @@
 
 @ExperimentalCoroutinesApi
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class AudioSharingRepositoryTest : SysuiTestCase() {
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
index f06b105..cee17c3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDeviceMetadataInteractorTest.kt
@@ -18,7 +18,9 @@
 
 import android.bluetooth.BluetoothAdapter
 import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.Drawable
 import android.testing.TestableLooper
+import android.util.Pair
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
@@ -64,6 +66,7 @@
     @Mock private lateinit var bluetoothDevice1: BluetoothDevice
     @Mock private lateinit var cachedDevice2: CachedBluetoothDevice
     @Mock private lateinit var bluetoothDevice2: BluetoothDevice
+    @Mock private lateinit var drawable: Drawable
     @Captor
     private lateinit var argumentCaptor: ArgumentCaptor<BluetoothAdapter.OnMetadataChangedListener>
     private lateinit var interactor: BluetoothDeviceMetadataInteractor
@@ -77,12 +80,14 @@
             whenever(cachedDevice1.name).thenReturn(DEVICE_NAME)
             whenever(cachedDevice1.address).thenReturn(DEVICE_ADDRESS)
             whenever(cachedDevice1.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+            whenever(cachedDevice1.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
             whenever(bluetoothDevice1.address).thenReturn(DEVICE_ADDRESS)
 
             whenever(cachedDevice2.device).thenReturn(bluetoothDevice2)
             whenever(cachedDevice2.name).thenReturn(DEVICE_NAME)
             whenever(cachedDevice2.address).thenReturn(DEVICE_ADDRESS)
             whenever(cachedDevice2.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+            whenever(cachedDevice2.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
             whenever(bluetoothDevice2.address).thenReturn(DEVICE_ADDRESS)
 
             interactor = bluetoothDeviceMetadataInteractor
@@ -175,14 +180,14 @@
                     .addOnMetadataChangedListener(
                         eq(bluetoothDevice1),
                         any(),
-                        argumentCaptor.capture()
+                        argumentCaptor.capture(),
                     )
 
                 val listener = argumentCaptor.value
                 listener.onMetadataChanged(
                     bluetoothDevice1,
                     BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY,
-                    ByteArray(0)
+                    ByteArray(0),
                 )
                 assertThat(update).isEqualTo(Unit)
             }
@@ -203,14 +208,14 @@
                     .addOnMetadataChangedListener(
                         eq(bluetoothDevice1),
                         any(),
-                        argumentCaptor.capture()
+                        argumentCaptor.capture(),
                     )
 
                 val listener = argumentCaptor.value
                 listener.onMetadataChanged(
                     bluetoothDevice1,
                     BluetoothDevice.METADATA_MODEL_NAME,
-                    ByteArray(0)
+                    ByteArray(0),
                 )
 
                 assertThat(update).isNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
index 566cd70..10bf523 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
@@ -35,7 +35,8 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
 import com.android.systemui.telephony.data.repository.fakeTelephonyRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
@@ -78,7 +79,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+        mobileConnectionsRepository = kosmos.mobileConnectionsRepository.fake
 
         overrideResource(R.string.lockscreen_emergency_call, MESSAGE_EMERGENCY_CALL)
         overrideResource(R.string.lockscreen_return_to_call, MESSAGE_RETURN_TO_CALL)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
index 82918a5..af2d7e4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalMetricsLoggerTest.kt
@@ -47,20 +47,14 @@
 
     @Test
     fun logAddWidget_componentNotLoggable_doNotLog() {
-        underTest.logAddWidget(
-            componentName = "com.green.package/my_test_widget",
-            rank = 1,
-        )
+        underTest.logAddWidget(componentName = "com.green.package/my_test_widget", rank = 1)
         verify(statsLogProxy, never())
-            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
     }
 
     @Test
     fun logAddWidget_componentLoggable_logAddEvent() {
-        underTest.logAddWidget(
-            componentName = "com.blue.package/my_test_widget",
-            rank = 1,
-        )
+        underTest.logAddWidget(componentName = "com.blue.package/my_test_widget", rank = 1)
         verify(statsLogProxy)
             .writeCommunalHubWidgetEventReported(
                 SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__ADD,
@@ -71,20 +65,14 @@
 
     @Test
     fun logRemoveWidget_componentNotLoggable_doNotLog() {
-        underTest.logRemoveWidget(
-            componentName = "com.yellow.package/my_test_widget",
-            rank = 2,
-        )
+        underTest.logRemoveWidget(componentName = "com.yellow.package/my_test_widget", rank = 2)
         verify(statsLogProxy, never())
-            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
     }
 
     @Test
     fun logRemoveWidget_componentLoggable_logRemoveEvent() {
-        underTest.logRemoveWidget(
-            componentName = "com.red.package/my_test_widget",
-            rank = 2,
-        )
+        underTest.logRemoveWidget(componentName = "com.red.package/my_test_widget", rank = 2)
         verify(statsLogProxy)
             .writeCommunalHubWidgetEventReported(
                 SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__REMOVE,
@@ -95,20 +83,14 @@
 
     @Test
     fun logTapWidget_componentNotLoggable_doNotLog() {
-        underTest.logTapWidget(
-            componentName = "com.yellow.package/my_test_widget",
-            rank = 2,
-        )
+        underTest.logTapWidget(componentName = "com.yellow.package/my_test_widget", rank = 2)
         verify(statsLogProxy, never())
-            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt())
+            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
     }
 
     @Test
     fun logTapWidget_componentLoggable_logRemoveEvent() {
-        underTest.logTapWidget(
-            componentName = "com.red.package/my_test_widget",
-            rank = 2,
-        )
+        underTest.logTapWidget(componentName = "com.red.package/my_test_widget", rank = 2)
         verify(statsLogProxy)
             .writeCommunalHubWidgetEventReported(
                 SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__TAP,
@@ -140,4 +122,43 @@
             )
         assertThat(statsEvents).hasSize(1)
     }
+
+    @Test
+    fun logResizeWidget_componentNotLoggable_doNotLog() {
+        underTest.logResizeWidget(
+            componentName = "com.green.package/my_test_widget",
+            rank = 1,
+            spanY = 2,
+        )
+        verify(statsLogProxy, never())
+            .writeCommunalHubWidgetEventReported(anyInt(), any(), anyInt(), anyInt())
+    }
+
+    @Test
+    fun logResizeWidget_componentLoggable_logResizeEvent() {
+        underTest.logResizeWidget(
+            componentName = "com.blue.package/my_test_widget",
+            rank = 1,
+            spanY = 2,
+        )
+        verify(statsLogProxy)
+            .writeCommunalHubWidgetEventReported(
+                SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+                "com.blue.package/my_test_widget",
+                rank = 1,
+                spanY = 2,
+            )
+    }
+
+    @Test
+    fun logResizeWidget_defaultSpanY_usesDefaultValue() {
+        underTest.logResizeWidget(componentName = "com.blue.package/my_test_widget", rank = 1)
+        verify(statsLogProxy)
+            .writeCommunalHubWidgetEventReported(
+                SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+                "com.blue.package/my_test_widget",
+                rank = 1,
+                spanY = 0,
+            )
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
index baeb2dd..0084e18 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt
@@ -16,38 +16,64 @@
 
 package com.android.systemui.communal.ui.viewmodel
 
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(AndroidJUnit4::class)
-class CommunalTransitionViewModelTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class CommunalTransitionViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
+
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf().andSceneContainer()
+        }
+    }
+
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags)
+    }
+
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
 
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val communalSceneRepository = kosmos.fakeCommunalSceneRepository
+    private val sceneInteractor = kosmos.sceneInteractor
 
     private val underTest: CommunalTransitionViewModel by lazy {
         kosmos.communalTransitionViewModel
     }
 
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @Test
     fun testIsUmoOnCommunalDuringTransitionBetweenLockscreenAndGlanceableHub() =
         testScope.runTest {
@@ -61,6 +87,7 @@
             assertThat(isUmoOnCommunal).isFalse()
         }
 
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @Test
     fun testIsUmoOnCommunalDuringTransitionBetweenDreamingAndGlanceableHub() =
         testScope.runTest {
@@ -74,6 +101,7 @@
             assertThat(isUmoOnCommunal).isFalse()
         }
 
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @Test
     fun testIsUmoOnCommunalDuringTransitionBetweenOccludedAndGlanceableHub() =
         testScope.runTest {
@@ -87,6 +115,7 @@
             assertThat(isUmoOnCommunal).isFalse()
         }
 
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @Test
     fun isUmoOnCommunal_noLongerVisible_returnsFalse() =
         testScope.runTest {
@@ -103,6 +132,7 @@
             assertThat(isUmoOnCommunal).isFalse()
         }
 
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @Test
     fun isUmoOnCommunal_idleOnCommunal_returnsTrue() =
         testScope.runTest {
@@ -116,11 +146,25 @@
             assertThat(isUmoOnCommunal).isTrue()
         }
 
+    @EnableFlags(FLAG_SCENE_CONTAINER)
+    @Test
+    fun isUmoOnCommunal_sceneContainerEnabled_idleOnCommunal_returnsTrue() =
+        testScope.runTest {
+            val isUmoOnCommunal by collectLastValue(underTest.isUmoOnCommunal)
+            assertThat(isUmoOnCommunal).isFalse()
+
+            // Change to communal scene.
+            setIdleScene(Scenes.Communal)
+
+            // isUmoOnCommunal returns true, even without any keyguard transition.
+            assertThat(isUmoOnCommunal).isTrue()
+        }
+
     private suspend fun TestScope.enterCommunal(from: KeyguardState) {
         keyguardTransitionRepository.sendTransitionSteps(
             from = from,
             to = KeyguardState.GLANCEABLE_HUB,
-            testScope
+            testScope,
         )
         communalSceneRepository.changeScene(CommunalScenes.Communal)
         runCurrent()
@@ -130,9 +174,17 @@
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.GLANCEABLE_HUB,
             to = to,
-            testScope
+            testScope,
         )
         communalSceneRepository.changeScene(CommunalScenes.Blank)
         runCurrent()
     }
+
+    private fun setIdleScene(scene: SceneKey) {
+        sceneInteractor.changeScene(scene, "test")
+        val transitionState =
+            MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(scene))
+        sceneInteractor.setTransitionState(transitionState)
+        testScope.runCurrent()
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index cecc11e..5bbd3ff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.media.controls.ui.controller.mediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.testKosmos
@@ -133,6 +134,7 @@
                 accessibilityManager,
                 packageManager,
                 WIDGET_PICKER_PACKAGE_NAME,
+                kosmos.mediaCarouselController,
             )
     }
 
@@ -353,6 +355,32 @@
         assertThat(event.contentDescription).isEqualTo("Test Clock widget added to lock screen")
     }
 
+    @Test
+    fun onResizeWidget_logsMetrics() =
+        testScope.runTest {
+            val appWidgetId = 123
+            val spanY = 2
+            val widgetIdToRankMap = mapOf(appWidgetId to 1)
+            val componentName = ComponentName("test.package", "TestWidget")
+            val rank = 1
+
+            underTest.onResizeWidget(
+                appWidgetId = appWidgetId,
+                spanY = spanY,
+                widgetIdToRankMap = widgetIdToRankMap,
+                componentName = componentName,
+                rank = rank,
+            )
+
+            verify(communalInteractor).resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+            verify(metricsLogger)
+                .logResizeWidget(
+                    componentName = componentName.flattenToString(),
+                    rank = rank,
+                    spanY = spanY,
+                )
+        }
+
     private companion object {
         val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
         const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 09daa51..3eba8ff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -69,6 +69,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
+import com.android.systemui.media.controls.ui.controller.mediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
 import com.android.systemui.power.domain.interactor.powerInteractor
@@ -178,6 +179,7 @@
             mediaHost,
             logcatLogBuffer("CommunalViewModelTest"),
             metricsLogger,
+            kosmos.mediaCarouselController,
         )
     }
 
@@ -627,10 +629,7 @@
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Communal),
                 stateTransition =
-                    TransitionStep(
-                        from = KeyguardState.DREAMING,
-                        to = KeyguardState.GLANCEABLE_HUB
-                    ),
+                    TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB),
             )
 
             // Then flow is not frozen
@@ -647,10 +646,7 @@
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Lockscreen),
                 stateTransition =
-                    TransitionStep(
-                        from = KeyguardState.GLANCEABLE_HUB,
-                        to = KeyguardState.OCCLUDED
-                    ),
+                    TransitionStep(from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED),
             )
 
             // Then flow is not frozen
@@ -735,10 +731,7 @@
             kosmos.setTransition(
                 sceneTransition = Idle(Scenes.Communal),
                 stateTransition =
-                    TransitionStep(
-                        from = KeyguardState.DREAMING,
-                        to = KeyguardState.GLANCEABLE_HUB
-                    ),
+                    TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB),
             )
 
             // Widgets available
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayScopeRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java
index eb72f29..3347180 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -48,10 +48,10 @@
 import android.app.ActivityManager;
 import android.content.res.Configuration;
 import android.hardware.display.AmbientDisplayConfiguration;
-import androidx.test.annotation.UiThreadTest;
 import android.view.Display;
 
 import androidx.annotation.NonNull;
+import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index 8062358..a65e7ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -19,7 +19,9 @@
 import android.content.ComponentName
 import android.content.Intent
 import android.os.RemoteException
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
 import android.service.dreams.Flags
 import android.service.dreams.IDreamOverlay
 import android.service.dreams.IDreamOverlayCallback
@@ -33,7 +35,6 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LifecycleRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.app.viewcapture.ViewCapture
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
@@ -43,6 +44,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.ambient.touch.TouchMonitor
 import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent
@@ -62,12 +64,16 @@
 import com.android.systemui.complication.dagger.ComplicationComponent
 import com.android.systemui.dreams.complication.HideComplicationTouchHandler
 import com.android.systemui.dreams.dagger.DreamOverlayComponent
+import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.gesture.domain.gestureInteractor
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.navigationbar.gestural.domain.GestureInteractor
 import com.android.systemui.navigationbar.gestural.domain.TaskInfo
 import com.android.systemui.navigationbar.gestural.domain.TaskMatcher
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.android.systemui.touch.TouchInsetManager
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -98,12 +104,14 @@
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verifyNoMoreInteractions
 import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidJUnit4::class)
-class DreamOverlayServiceTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() {
     private val mFakeSystemClock = FakeSystemClock()
     private val mMainExecutor = FakeExecutor(mFakeSystemClock)
     private val kosmos = testKosmos()
@@ -245,6 +253,10 @@
         )
     }
 
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags!!)
+    }
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
@@ -287,6 +299,7 @@
                 mKeyguardUpdateMonitor,
                 mScrimManager,
                 mCommunalInteractor,
+                kosmos.sceneInteractor,
                 mSystemDialogsCloser,
                 mUiEventLogger,
                 mTouchInsetManager,
@@ -768,6 +781,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     @kotlin.Throws(RemoteException::class)
     fun testTransitionToGlanceableHub() =
         testScope.runTest {
@@ -793,6 +807,35 @@
         }
 
     @Test
+    @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_SCENE_CONTAINER, FLAG_COMMUNAL_HUB)
+    @kotlin.Throws(RemoteException::class)
+    fun testTransitionToGlanceableHub_sceneContainer() =
+        testScope.runTest {
+            // Inform the overlay service of dream starting. Do not show dream complications.
+            client.startDream(
+                mWindowParams,
+                mDreamOverlayCallback,
+                DREAM_COMPONENT,
+                false /*isPreview*/,
+                false, /*shouldShowComplication*/
+            )
+            mMainExecutor.runAllReady()
+
+            verify(mDreamOverlayCallback).onRedirectWake(false)
+            clearInvocations(mDreamOverlayCallback)
+            kosmos.setCommunalAvailable(true)
+            mMainExecutor.runAllReady()
+            runCurrent()
+            verify(mDreamOverlayCallback).onRedirectWake(true)
+            client.onWakeRequested()
+            mMainExecutor.runAllReady()
+            runCurrent()
+            assertThat(kosmos.sceneContainerRepository.currentScene.value)
+                .isEqualTo(Scenes.Communal)
+            verify(mUiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START)
+        }
+
+    @Test
     @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB)
     @Throws(RemoteException::class)
     fun testRedirectExit() =
@@ -911,6 +954,7 @@
     // Verifies that the touch handling lifecycle is STARTED even if the dream starts while not
     // focused.
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun testLifecycle_dreamNotFocusedOnStart_isStarted() {
         val transitionState: MutableStateFlow<ObservableTransitionState> =
             MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))
@@ -1024,6 +1068,7 @@
     }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun testCommunalVisible_setsLifecycleState() {
         val client = client
 
@@ -1060,6 +1105,7 @@
 
     // Verifies the dream's lifecycle
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun testLifecycleStarted_whenAnyOcclusion() {
         val client = client
 
@@ -1256,5 +1302,11 @@
             ComponentName("package", "homeControlPanel")
         private const val DREAM_COMPONENT = "package/dream"
         private const val WINDOW_NAME = "test"
+
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_HUB).andSceneContainer()
+        }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
new file mode 100644
index 0000000..aacfaed
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.dreams.ui.viewmodel
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+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.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.shade.shared.flag.DualShade
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableSceneContainer
+class DreamUserActionsViewModelTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private lateinit var underTest: DreamUserActionsViewModel
+
+    @Before
+    fun setUp() {
+        underTest = kosmos.dreamUserActionsViewModel
+        underTest.activateIn(testScope)
+    }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun actions_singleShade() =
+        testScope.runTest {
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = true,
+                shadeMode = ShadeMode.Single,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun actions_splitShade() =
+        testScope.runTest {
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = true,
+                shadeMode = ShadeMode.Split,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun actions_dualShade() =
+        testScope.runTest {
+            val actions by collectLastValue(underTest.actions)
+
+            setUpState(
+                isShadeTouchable = true,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Dual,
+            )
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(
+                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+                )
+
+            setUpState(
+                isShadeTouchable = false,
+                isDeviceUnlocked = false,
+                shadeMode = ShadeMode.Dual,
+            )
+            assertThat(actions).isEmpty()
+
+            setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual)
+            assertThat(actions).isNotEmpty()
+            assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
+            assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
+            assertThat(actions?.get(Swipe.Down))
+                .isEqualTo(
+                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
+                )
+        }
+
+    private fun TestScope.setUpState(
+        isShadeTouchable: Boolean,
+        isDeviceUnlocked: Boolean,
+        shadeMode: ShadeMode,
+    ) {
+        if (isShadeTouchable) {
+            kosmos.powerInteractor.setAwakeForTest()
+        } else {
+            kosmos.powerInteractor.setAsleepForTest()
+        }
+
+        if (isDeviceUnlocked) {
+            unlockDevice()
+        } else {
+            lockDevice()
+        }
+
+        if (shadeMode == ShadeMode.Dual) {
+            assertThat(DualShade.isEnabled).isTrue()
+        } else {
+            assertThat(DualShade.isEnabled).isFalse()
+            kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode == ShadeMode.Split)
+        }
+        runCurrent()
+    }
+
+    private fun TestScope.lockDevice() {
+        val deviceUnlockStatus by
+            collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+
+        kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+        assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+        kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+        runCurrent()
+    }
+
+    private fun TestScope.unlockDevice() {
+        val deviceUnlockStatus by
+            collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
+
+        kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+            SuccessFingerprintAuthenticationStatus(0, true)
+        )
+        assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+        kosmos.sceneInteractor.changeScene(Scenes.Gone, "reason")
+        runCurrent()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
index 5efb617..f6a6e54 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt
@@ -119,22 +119,6 @@
         }
 
     @Test
-    fun onLongClick_whenTileDoesNotHandleLongClick_playsFailureHaptics() =
-        testScope.runTest {
-            // WHEN the tile is long-clicked but the tile does not handle a long-click
-            val state = QSTile.State().apply { handlesLongClick = false }
-            qsTile.changeState(state)
-            underTest.setTileInteractionState(
-                TileHapticsViewModel.TileInteractionState.LONG_CLICKED
-            )
-            runCurrent()
-
-            // THEN the failure token plays
-            assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
-            assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
-        }
-
-    @Test
     fun whenLaunchingFromClick_doesNotPlayHaptics() =
         testScope.runTest {
             // WHEN the tile is clicked and its action state changes accordingly
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
index c646d8f..cc4c7c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepositoryTest.kt
@@ -218,11 +218,11 @@
             simpleShortcutCategory(System, "System controls", "View recent apps"),
             simpleShortcutCategory(AppCategories, "Applications", "Calculator"),
             simpleShortcutCategory(AppCategories, "Applications", "Calendar"),
-            simpleShortcutCategory(AppCategories, "Applications", "Chrome"),
+            simpleShortcutCategory(AppCategories, "Applications", "Browser"),
             simpleShortcutCategory(AppCategories, "Applications", "Contacts"),
-            simpleShortcutCategory(AppCategories, "Applications", "Gmail"),
+            simpleShortcutCategory(AppCategories, "Applications", "Email"),
             simpleShortcutCategory(AppCategories, "Applications", "Maps"),
-            simpleShortcutCategory(AppCategories, "Applications", "Messages"),
+            simpleShortcutCategory(AppCategories, "Applications", "SMS"),
             simpleShortcutCategory(MultiTasking, "Recent apps", "Cycle forward through recent apps"),
         )
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
index 4e429c3..69fb03d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt
@@ -47,7 +47,8 @@
 import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY_FINGERPRINT
 import com.android.systemui.keyguard.shared.model.DevicePosture
 import com.android.systemui.res.R
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
@@ -99,7 +100,7 @@
     private lateinit var devicePostureRepository: FakeDevicePostureRepository
     private lateinit var facePropertyRepository: FakeFacePropertyRepository
     private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
-    private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
+    private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository
 
     private lateinit var testDispatcher: TestDispatcher
     private lateinit var testScope: TestScope
@@ -142,7 +143,7 @@
             1,
             SensorStrength.STRONG,
             FingerprintSensorType.UDFPS_OPTICAL,
-            emptyMap()
+            emptyMap(),
         )
         verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture())
         verify(authController, times(2)).addCallback(authControllerCallback.capture())
@@ -247,7 +248,7 @@
     private fun deviceIsInPostureThatSupportsFaceAuth() {
         overrideResource(
             R.integer.config_face_auth_supported_posture,
-            DevicePostureController.DEVICE_POSTURE_FLIPPED
+            DevicePostureController.DEVICE_POSTURE_FLIPPED,
         )
         devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED)
     }
@@ -459,7 +460,7 @@
 
             biometricsAreEnabledBySettings()
             doNotDisableKeyguardAuthFeatures()
-            mobileConnectionsRepository.isAnySimSecure.value = false
+            mobileConnectionsRepository.fake.isAnySimSecure.value = false
             runCurrent()
 
             val isFaceAuthEnabledAndEnrolled by
@@ -467,7 +468,7 @@
 
             assertThat(isFaceAuthEnabledAndEnrolled).isTrue()
 
-            mobileConnectionsRepository.isAnySimSecure.value = true
+            mobileConnectionsRepository.fake.isAnySimSecure.value = true
             runCurrent()
 
             assertThat(isFaceAuthEnabledAndEnrolled).isFalse()
@@ -485,13 +486,13 @@
             doNotDisableKeyguardAuthFeatures()
             faceAuthIsStrongBiometric()
             biometricsAreEnabledBySettings()
-            mobileConnectionsRepository.isAnySimSecure.value = false
+            mobileConnectionsRepository.fake.isAnySimSecure.value = false
 
             onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
             onNonStrongAuthChanged(false, PRIMARY_USER_ID)
             assertThat(isFaceAuthCurrentlyAllowed).isTrue()
 
-            mobileConnectionsRepository.isAnySimSecure.value = true
+            mobileConnectionsRepository.fake.isAnySimSecure.value = true
             assertThat(isFaceAuthCurrentlyAllowed).isFalse()
         }
 
@@ -584,7 +585,7 @@
         testScope.runTest {
             overrideResource(
                 R.integer.config_face_auth_supported_posture,
-                DevicePostureController.DEVICE_POSTURE_UNKNOWN
+                DevicePostureController.DEVICE_POSTURE_UNKNOWN,
             )
 
             createBiometricSettingsRepository()
@@ -597,7 +598,7 @@
         testScope.runTest {
             overrideResource(
                 R.integer.config_face_auth_supported_posture,
-                DevicePostureController.DEVICE_POSTURE_FLIPPED
+                DevicePostureController.DEVICE_POSTURE_FLIPPED,
             )
 
             createBiometricSettingsRepository()
@@ -749,7 +750,7 @@
                 1,
                 SensorStrength.STRONG,
                 FingerprintSensorType.UDFPS_OPTICAL,
-                emptyMap()
+                emptyMap(),
             )
             // Non strong auth is not allowed now, FP is marked strong
             onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID)
@@ -761,7 +762,7 @@
                 1,
                 SensorStrength.CONVENIENCE,
                 FingerprintSensorType.UDFPS_OPTICAL,
-                emptyMap()
+                emptyMap(),
             )
             assertThat(isFingerprintCurrentlyAllowed).isFalse()
 
@@ -769,7 +770,7 @@
                 1,
                 SensorStrength.WEAK,
                 FingerprintSensorType.UDFPS_OPTICAL,
-                emptyMap()
+                emptyMap(),
             )
             assertThat(isFingerprintCurrentlyAllowed).isFalse()
         }
@@ -791,7 +792,7 @@
                 1,
                 SensorStrength.STRONG,
                 FingerprintSensorType.UDFPS_OPTICAL,
-                emptyMap()
+                emptyMap(),
             )
             // Non strong auth is not allowed now, FP is marked strong
             onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID)
@@ -830,7 +831,7 @@
             UserInfo(
                 /* id= */ PRIMARY_USER_ID,
                 /* name= */ "primary user",
-                /* flags= */ UserInfo.FLAG_PRIMARY
+                /* flags= */ UserInfo.FLAG_PRIMARY,
             )
 
         private const val ANOTHER_USER_ID = 1
@@ -838,7 +839,7 @@
             UserInfo(
                 /* id= */ ANOTHER_USER_ID,
                 /* name= */ "another user",
-                /* flags= */ UserInfo.FLAG_PRIMARY
+                /* flags= */ UserInfo.FLAG_PRIMARY,
             )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
index 5a597fe..f537e32 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepositoryImplTest.kt
@@ -50,7 +50,6 @@
         fakeSettings.userId = fakeUserTracker.userId
         underTest =
             KeyguardSmartspaceRepositoryImpl(
-                context = context,
                 secureSettings = fakeSettings,
                 userTracker = fakeUserTracker,
                 applicationScope = scope.backgroundScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 3d5498b..7a3089f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -527,6 +527,29 @@
             assertEquals(0, steps.size)
         }
 
+    @Test
+    fun testForceFinishCurrentTransition_noTransitionRunning_unlocksMutex() =
+        testScope.runTest {
+            val steps by collectValues(underTest.transitions.dropWhile { step -> step.from == OFF })
+            underTest.forceFinishCurrentTransition()
+
+            assertThat(steps.isEmpty())
+
+            underTest.forceFinishCurrentTransition()
+            runCurrent()
+
+            assertThat(steps.isEmpty())
+            runner.startTransition(
+                this,
+                TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, getAnimator()),
+                maxFrames = 100,
+            )
+
+            advanceTimeBy(5000L)
+
+            assertThat(steps.isNotEmpty())
+        }
+
     private fun listWithStep(
         step: BigDecimal,
         start: BigDecimal = BigDecimal.ZERO,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
index aee72de2..28ac169 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractorTest.kt
@@ -310,7 +310,7 @@
         // read during initialization to set up flows. Maybe there is a better way to handle that.
         underTest =
             KeyguardTouchHandlingInteractor(
-                appContext = mContext,
+                context = mContext,
                 scope = testScope.backgroundScope,
                 transitionInteractor = kosmos.keyguardTransitionInteractor,
                 repository = keyguardRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/power/PowerUITest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/power/PowerUITest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 93dede5..f1f6c61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -38,7 +38,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.res.R;
 import com.android.systemui.retail.data.repository.FakeRetailModeRepository;
-import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl;
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSecurityFooterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSSecurityFooterTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
index b72668b..921a8a6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt
@@ -41,8 +41,8 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.largeScreenHeaderHelper
 import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.sysuiStatusBarStateController
 import com.android.systemui.util.animation.DisappearParameters
 import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
index 6fce108..ee2a1d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
@@ -19,10 +19,10 @@
 import android.animation.AnimatorTestRule
 import android.content.Context
 import android.service.quicksettings.Tile
-import android.testing.AndroidTestingRunner
 import android.view.ContextThemeWrapper
 import android.view.View
 import android.widget.ImageView
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.annotation.UiThreadTest
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@
 import org.junit.runner.RunWith
 
 /** Test for regression b/311121830 and b/323125376 */
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @UiThreadTest
 @SmallTest
 class QSIconViewImplTest_311121830 : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
index ba7a65d..47bfda4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
index b536520..b47dcb5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.retail.data.repository.FakeRetailModeRepository
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
index bf97afe..9590816 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -194,6 +195,24 @@
                 .isFalse()
         }
 
+    @Test
+    fun invisibleDueToOcclusion_isDreaming_emitsTrue() =
+        testScope.runTest {
+            val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
+
+            // Verify that we start with unoccluded
+            assertWithMessage("Should start unoccluded").that(invisibleDueToOcclusion).isFalse()
+
+            // Start dreaming, which is an occluding activity
+            showOccludingActivity()
+            kosmos.keyguardInteractor.setDreaming(true)
+
+            // Verify not invisible when dreaming
+            assertWithMessage("Should be invisible when dreaming")
+                .that(invisibleDueToOcclusion)
+                .isTrue()
+        }
+
     /** Simulates the appearance of a show-when-locked `Activity` in the foreground. */
     private fun TestScope.showOccludingActivity() {
         keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index af0274b..2e074da 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -73,6 +73,7 @@
 import com.android.systemui.keyguard.data.repository.keyguardRepository
 import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.keyguard.dismissCallbackRegistry
+import com.android.systemui.keyguard.domain.interactor.dozeInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.scenetransition.lockscreenSceneTransitionInteractor
@@ -143,6 +144,8 @@
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor }
+    private val dozeInteractor by lazy { kosmos.dozeInteractor }
+    private val keyguardInteractor by lazy { kosmos.keyguardInteractor }
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
     private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
@@ -373,6 +376,64 @@
         }
 
     @Test
+    fun hydrateVisibility_whileDreaming() =
+        testScope.runTest {
+            val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+            // GIVEN the device is dreaming
+            val transitionState =
+                prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Dream)
+            underTest.start()
+            assertThat(isVisible).isFalse()
+        }
+
+    @Test
+    fun hydrateVisibility_onCommunalWhileOccluded() =
+        testScope.runTest {
+            val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+            kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
+                true,
+                mock(),
+            )
+            prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Communal)
+            underTest.start()
+            runCurrent()
+            assertThat(isVisible).isTrue()
+        }
+
+    @Test
+    fun hydrateVisibility_inCommunalTransition() =
+        testScope.runTest {
+            val isVisible by collectLastValue(sceneInteractor.isVisible)
+
+            // GIVEN the device is dreaming
+            val transitionState =
+                prepareState(
+                    authenticationMethod = AuthenticationMethodModel.Pin,
+                    isDeviceUnlocked = false,
+                    initialSceneKey = Scenes.Dream,
+                )
+            underTest.start()
+            assertThat(isVisible).isFalse()
+
+            // WHEN a transition starts to the communal hub
+            sceneInteractor.changeScene(Scenes.Dream, "switching to dream for test")
+            transitionState.value =
+                ObservableTransitionState.Transition(
+                    fromScene = Scenes.Dream,
+                    toScene = Scenes.Communal,
+                    currentScene = flowOf(Scenes.Dream),
+                    progress = flowOf(0.5f),
+                    isInitiatedByUserInput = true,
+                    isUserInputOngoing = flowOf(false),
+                )
+            runCurrent()
+            // THEN scenes are visible
+            assertThat(isVisible).isTrue()
+        }
+
+    @Test
     fun startsInLockscreenScene() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -643,7 +704,7 @@
     fun switchToAOD_whenAvailable_whenDeviceSleepsLocked() =
         testScope.runTest {
             kosmos.lockscreenSceneTransitionInteractor.start()
-            val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState)
+            val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState)
             val currentTransitionInfo by
                 collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
             val transitionState =
@@ -673,7 +734,7 @@
     fun switchToDozing_whenAodUnavailable_whenDeviceSleepsLocked() =
         testScope.runTest {
             kosmos.lockscreenSceneTransitionInteractor.start()
-            val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState)
+            val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState)
             val currentTransitionInfo by
                 collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
             val transitionState =
@@ -2360,6 +2421,66 @@
         }
 
     @Test
+    fun stayOnLockscreen_whenDozingStarted() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            prepareState()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            underTest.start()
+
+            // Stay on Lockscreen when dozing and dreaming
+            dozeInteractor.setIsDozing(true)
+            keyguardInteractor.setDreaming(true)
+            kosmos.fakeKeyguardRepository.setDreamingWithOverlay(false)
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+        }
+
+    @Test
+    fun switchFromLockscreenToDream_whenDreamStarted() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            prepareState()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            underTest.start()
+
+            powerInteractor.setAwakeForTest()
+            keyguardInteractor.setDreaming(true)
+            // Move past initial delay with [KeyguardInteractor#isAbleToDream]
+            advanceTimeBy(600L)
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Dream)
+        }
+
+    @Test
+    fun switchFromDreamToLockscreen_whenLockedAndDreamStopped() =
+        testScope.runTest {
+            keyguardInteractor.setDreaming(true)
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            prepareState(initialSceneKey = Scenes.Dream)
+            assertThat(currentScene).isEqualTo(Scenes.Dream)
+            underTest.start()
+
+            keyguardInteractor.setDreaming(false)
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+        }
+
+    @Test
+    fun switchFromDreamToGone_whenUnlockedAndDreamStopped() =
+        testScope.runTest {
+            keyguardInteractor.setDreaming(true)
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            prepareState(initialSceneKey = Scenes.Dream, isDeviceUnlocked = true)
+            assertThat(currentScene).isEqualTo(Scenes.Dream)
+            underTest.start()
+
+            keyguardInteractor.setDreaming(false)
+            runCurrent()
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+        }
+
+    @Test
     fun replacesLockscreenSceneOnBackStack_whenUnlockdViaAlternateBouncer_fromShade() =
         testScope.runTest {
             val transitionState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
index a10d81f..1413204 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
@@ -20,8 +20,8 @@
 import android.content.Intent
 import android.os.Bundle
 import android.os.UserHandle
-import android.testing.AndroidTestingRunner
 import android.view.Window
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.argumentCaptor
@@ -39,7 +39,7 @@
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.verifyBlocking
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class ActionExecutorTest : SysuiTestCase() {
     private val scheduler = TestCoroutineScheduler()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
index c5070286..84b7d10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ScreenshotDetectionControllerTest.kt
@@ -21,10 +21,10 @@
 import android.content.pm.PackageManager
 import android.content.pm.PackageManager.MATCH_ANY_USER
 import android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS
-import android.testing.AndroidTestingRunner
 import android.view.Display
 import android.view.IWindowManager
 import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argThat
@@ -43,7 +43,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class ScreenshotDetectionControllerTest {
 
     @Mock lateinit var windowManager: IWindowManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 77b5c91..d2eca0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -23,9 +23,9 @@
 import android.net.Uri
 import android.os.UserHandle
 import android.os.UserManager
-import android.testing.AndroidTestingRunner
 import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.internal.util.ScreenshotRequest
 import com.android.systemui.SysuiTestCase
@@ -49,7 +49,7 @@
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class TakeScreenshotServiceTest : SysuiTestCase() {
 
     private val userManager = mock<UserManager> { on { isUserUnlocked } doReturn (true) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/policy/PolicyRequestProcessorTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 01c17bd..94a19c8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -148,7 +148,6 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
@@ -428,7 +427,7 @@
         mShadeInteractor = new ShadeInteractorImpl(
                 mTestScope.getBackgroundScope(),
                 mKosmos.getDeviceProvisioningInteractor(),
-                new FakeDisableFlagsRepository(),
+                mKosmos.getDisableFlagsInteractor(),
                 mDozeParameters,
                 mFakeKeyguardRepository,
                 mKeyguardTransitionInteractor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 443595d..ef132d5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -149,7 +149,7 @@
     @Mock protected LargeScreenHeaderHelper mLargeScreenHeaderHelper;
 
     protected FakeDisableFlagsRepository mDisableFlagsRepository =
-            new FakeDisableFlagsRepository();
+            mKosmos.getFakeDisableFlagsRepository();
     protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
     protected FakeShadeRepository mShadeRepository = new FakeShadeRepository();
 
@@ -185,7 +185,7 @@
         mShadeInteractor = new ShadeInteractorImpl(
                 mTestScope.getBackgroundScope(),
                 mKosmos.getDeviceProvisioningInteractor(),
-                mDisableFlagsRepository,
+                mKosmos.getDisableFlagsInteractor(),
                 mDozeParameters,
                 mKeyguardRepository,
                 keyguardTransitionInteractor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
index 46961d4..ee3f801 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt
@@ -19,7 +19,7 @@
 import android.app.StatusBarManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.cancelChildren
@@ -61,7 +61,7 @@
             mDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
                     StatusBarManager.DISABLE_NONE,
-                    StatusBarManager.DISABLE2_QUICK_SETTINGS
+                    StatusBarManager.DISABLE2_QUICK_SETTINGS,
                 )
             runCurrent()
 
@@ -76,7 +76,7 @@
             mDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(
                     StatusBarManager.DISABLE_NONE,
-                    StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+                    StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
                 )
             runCurrent()
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 9a8df33..cd55bb2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -38,11 +38,11 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.CarrierTextManager;
@@ -76,7 +76,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @SmallTest
 public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
similarity index 95%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
index a9a5cac..4e7839e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
@@ -34,13 +34,13 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class ShadePositionRepositoryTest : SysuiTestCase() {
+class ShadeDisplaysRepositoryTest : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val commandRegistry = kosmos.commandRegistry
     private val pw = PrintWriter(StringWriter())
 
-    private val underTest = ShadePositionRepositoryImpl(commandRegistry)
+    private val underTest = ShadeDisplaysRepositoryImpl(commandRegistry)
 
     @Before
     fun setUp() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
new file mode 100644
index 0000000..8ef1e56
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.shade.domain.interactor
+
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.view.Display
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.FakeDisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
+import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.advanceUntilIdle
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ShadeDisplaysInteractorTest : SysuiTestCase() {
+
+    private val shadeRootview = mock<WindowRootView>()
+    private val positionRepository = FakeShadeDisplayRepository()
+    private val defaultContext = mock<Context>()
+    private val secondaryContext = mock<Context>()
+    private val contextStore = FakeDisplayWindowPropertiesRepository()
+    private val testScope = TestScope(UnconfinedTestDispatcher())
+    private val configurationForwarder = mock<ConfigurationForwarder>()
+    private val defaultWm = mock<WindowManager>()
+    private val secondaryWm = mock<WindowManager>()
+    private val resources = mock<Resources>()
+    private val configuration = mock<Configuration>()
+    private val display = mock<Display>()
+
+    private val interactor =
+        ShadeDisplaysInteractor(
+            shadeRootview,
+            positionRepository,
+            defaultContext,
+            contextStore,
+            testScope,
+            configurationForwarder,
+            testScope.coroutineContext,
+        )
+
+    @Before
+    fun setup() {
+        whenever(shadeRootview.display).thenReturn(display)
+        whenever(display.displayId).thenReturn(0)
+
+        whenever(resources.configuration).thenReturn(configuration)
+        whenever(resources.configuration).thenReturn(configuration)
+
+        whenever(defaultContext.displayId).thenReturn(0)
+        whenever(defaultContext.getSystemService(any())).thenReturn(defaultWm)
+        whenever(defaultContext.resources).thenReturn(resources)
+        contextStore.insert(
+            DisplayWindowProperties(
+                displayId = 0,
+                windowType = TYPE_NOTIFICATION_SHADE,
+                context = defaultContext,
+                windowManager = defaultWm,
+                layoutInflater = mock(),
+            )
+        )
+
+        whenever(secondaryContext.displayId).thenReturn(1)
+        whenever(secondaryContext.getSystemService(any())).thenReturn(secondaryWm)
+        whenever(secondaryContext.resources).thenReturn(resources)
+        contextStore.insert(
+            DisplayWindowProperties(
+                displayId = 1,
+                windowType = TYPE_NOTIFICATION_SHADE,
+                context = secondaryContext,
+                windowManager = secondaryWm,
+                layoutInflater = mock(),
+            )
+        )
+    }
+
+    @Test
+    fun start_shadeInCorrectPosition_notAddedOrRemoved() {
+        whenever(display.displayId).thenReturn(0)
+        positionRepository.setDisplayId(0)
+        interactor.start()
+        testScope.advanceUntilIdle()
+
+        verifyNoMoreInteractions(defaultWm)
+        verifyNoMoreInteractions(secondaryWm)
+    }
+
+    @Test
+    fun start_shadeInWrongPosition_changes() {
+        whenever(display.displayId).thenReturn(0)
+        positionRepository.setDisplayId(1)
+        interactor.start()
+        testScope.advanceUntilIdle()
+
+        verify(defaultWm).removeView(eq(shadeRootview))
+        verify(secondaryWm).addView(eq(shadeRootview), any())
+    }
+
+    @Test
+    fun start_shadePositionChanges_removedThenAdded() {
+        whenever(display.displayId).thenReturn(0)
+        positionRepository.setDisplayId(0)
+        interactor.start()
+        testScope.advanceUntilIdle()
+
+        positionRepository.setDisplayId(1)
+        testScope.advanceUntilIdle()
+
+        verify(defaultWm).removeView(eq(shadeRootview))
+        verify(secondaryWm).addView(eq(shadeRootview), any())
+    }
+
+    @Test
+    fun start_shadePositionChanges_newConfigPropagated() {
+        whenever(display.displayId).thenReturn(0)
+        positionRepository.setDisplayId(0)
+        interactor.start()
+        testScope.advanceUntilIdle()
+
+        positionRepository.setDisplayId(1)
+        testScope.advanceUntilIdle()
+
+        verify(configurationForwarder).onConfigurationChanged(eq(configuration))
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 19ac0cf..da652c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -37,8 +37,8 @@
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.shade.shadeTestUtil
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.phone.dozeParameters
 import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
 import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
index 907c684..cd07821 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt
@@ -32,7 +32,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index c8ef663..e974c2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -30,13 +30,13 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.testing.AndroidTestingRunner;
 import android.util.FloatProperty;
 import android.util.Property;
 import android.view.View;
 import android.view.animation.Interpolator;
 
 import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.app.animation.Interpolators;
@@ -51,7 +51,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @UiThreadTest
 public class PropertyAnimatorTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index e21a005..4ef9792 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -68,12 +68,12 @@
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -118,7 +118,7 @@
 import java.util.Map;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotifCollectionTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 9613f76..2c488e3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -28,7 +28,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager
 import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
 import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -52,6 +51,7 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
 import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -101,7 +101,7 @@
 
     private val notifPipeline: NotifPipeline = mock()
     private val logger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true)
-    private val headsUpManager: HeadsUpManagerPhone = mock()
+    private val headsUpManager: BaseHeadsUpManager = mock()
     private val headsUpViewBinder: HeadsUpViewBinder = mock()
     private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock()
     private val remoteInputManager: NotificationRemoteInputManager = mock()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
index ca75ca6..a70d24e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
@@ -28,43 +28,41 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderGroupListener
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.withArgCaptor
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.never
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.inOrder
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class RenderStageManagerTest : SysuiTestCase() {
 
-    @Mock private lateinit var shadeListBuilder: ShadeListBuilder
-    @Mock private lateinit var onAfterRenderListListener: OnAfterRenderListListener
-    @Mock private lateinit var onAfterRenderGroupListener: OnAfterRenderGroupListener
-    @Mock private lateinit var onAfterRenderEntryListener: OnAfterRenderEntryListener
+    private val shadeListBuilder: ShadeListBuilder = mock()
+    private val onAfterRenderListListener: OnAfterRenderListListener = mock()
+    private val onAfterRenderGroupListener: OnAfterRenderGroupListener = mock()
+    private val onAfterRenderEntryListener: OnAfterRenderEntryListener = mock()
 
-    private lateinit var onRenderListListener: ShadeListBuilder.OnRenderListListener
-    private lateinit var renderStageManager: RenderStageManager
     private val spyViewRenderer = spy(FakeNotifViewRenderer())
+    private lateinit var onRenderListListener: ShadeListBuilder.OnRenderListListener
+
+    private lateinit var renderStageManager: RenderStageManager
 
     @Before
     fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
         renderStageManager = RenderStageManager()
         renderStageManager.attach(shadeListBuilder)
-        onRenderListListener = withArgCaptor {
-            verify(shadeListBuilder).setOnRenderListListener(capture())
-        }
+
+        val captor = argumentCaptor<ShadeListBuilder.OnRenderListListener>()
+        verify(shadeListBuilder).setOnRenderListListener(captor.capture())
+        onRenderListListener = captor.lastValue
     }
 
     private fun setUpRenderer() {
@@ -89,7 +87,7 @@
         verifyNoMoreInteractions(
             onAfterRenderListListener,
             onAfterRenderGroupListener,
-            onAfterRenderEntryListener
+            onAfterRenderEntryListener,
         )
     }
 
@@ -171,7 +169,7 @@
         verifyNoMoreInteractions(
             onAfterRenderListListener,
             onAfterRenderGroupListener,
-            onAfterRenderEntryListener
+            onAfterRenderEntryListener,
         )
     }
 
@@ -191,30 +189,27 @@
         verifyNoMoreInteractions(
             onAfterRenderListListener,
             onAfterRenderGroupListener,
-            onAfterRenderEntryListener
+            onAfterRenderEntryListener,
         )
     }
 
-    private fun listWith2Groups8Entries() = listOf(
-        group(
-            notif(1),
-            notif(2),
-            notif(3)
-        ),
-        notif(4),
-        group(
-            notif(5),
-            notif(6),
-            notif(7)
-        ),
-        notif(8)
-    )
+    private fun listWith2Groups8Entries() =
+        listOf(
+            group(notif(1), notif(2), notif(3)),
+            notif(4),
+            group(notif(5), notif(6), notif(7)),
+            notif(8),
+        )
 
     private class FakeNotifViewRenderer : NotifViewRenderer {
         override fun onRenderList(notifList: List<ListEntry>) {}
+
         override fun getStackController(): NotifStackController = mock()
+
         override fun getGroupController(group: GroupEntry): NotifGroupController = mock()
+
         override fun getRowController(entry: NotificationEntry): NotifRowController = mock()
+
         override fun onDispatchComplete() {}
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
index 79ff4be..7eac7e8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
@@ -21,8 +21,8 @@
 import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
@@ -51,10 +51,7 @@
     fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() =
         with(testComponent) {
             disableFlags.disableFlags.value =
-                DisableFlagsModel(
-                    StatusBarManager.DISABLE_NONE,
-                    StatusBarManager.DISABLE2_NONE,
-                )
+                DisableFlagsModel(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE)
             assertThat(underTest.areNotificationAlertsEnabled()).isTrue()
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
index fd41921..371e1c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
@@ -16,13 +16,13 @@
 package com.android.systemui.statusbar.notification.row
 
 import android.content.Context
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.util.AttributeSet
 import android.view.View
 import android.widget.Button
 import android.widget.FrameLayout
 import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
@@ -38,7 +38,7 @@
 
 /** Tests for [NotifLayoutInflaterFactory] */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotifLayoutInflaterFactoryTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 3669e3d..b8745b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -21,12 +21,12 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
 import org.mockito.junit.MockitoRule;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class NotificationSectionsManagerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index b2a485c..b877456 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -32,23 +32,19 @@
 import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.AvalancheController
-import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
-import junit.framework.Assert.assertEquals
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import org.junit.Assume
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.any
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
 
@@ -846,7 +842,7 @@
         val viewStart = 0f
         val shelfStart = 1f
 
-        val expandableView = mock(ExpandableView::class.java)
+        val expandableView = mock<ExpandableView>()
         whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
         whenever(expandableView.hasExpandingChild()).thenReturn(false)
 
@@ -854,7 +850,7 @@
         expandableViewState.yTranslation = viewStart
 
         stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
-        assertFalse(expandableViewState.hidden)
+        assertThat(expandableViewState.hidden).isFalse()
     }
 
     @Test
@@ -862,7 +858,7 @@
         val shelfStart = 0f
         val viewStart = 1f
 
-        val expandableView = mock(ExpandableView::class.java)
+        val expandableView = mock<ExpandableView>()
         whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
         whenever(expandableView.hasExpandingChild()).thenReturn(false)
 
@@ -870,7 +866,7 @@
         expandableViewState.yTranslation = viewStart
 
         stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
-        assertTrue(expandableViewState.hidden)
+        assertThat(expandableViewState.hidden).isTrue()
     }
 
     @Test
@@ -878,7 +874,7 @@
         val shelfStart = 0f
         val viewStart = 1f
 
-        val expandableView = mock(ExpandableView::class.java)
+        val expandableView = mock<ExpandableView>()
         whenever(expandableView.isExpandAnimationRunning).thenReturn(true)
         whenever(expandableView.hasExpandingChild()).thenReturn(true)
 
@@ -886,7 +882,7 @@
         expandableViewState.yTranslation = viewStart
 
         stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
-        assertFalse(expandableViewState.hidden)
+        assertThat(expandableViewState.hidden).isFalse()
     }
 
     @Test
@@ -898,12 +894,12 @@
             expandableViewState,
             /* isShadeExpanded= */ true,
             /* mustStayOnScreen= */ true,
-            /* isViewEndVisible= */ true,
+            /* topVisible = */ true,
             /* viewEnd= */ 0f,
-            /* maxHunY= */ 10f,
+            /* hunMax = */ 10f,
         )
 
-        assertTrue(expandableViewState.headsUpIsVisible)
+        assertThat(expandableViewState.headsUpIsVisible).isTrue()
     }
 
     @Test
@@ -915,12 +911,12 @@
             expandableViewState,
             /* isShadeExpanded= */ true,
             /* mustStayOnScreen= */ true,
-            /* isViewEndVisible= */ true,
+            /* topVisible = */ true,
             /* viewEnd= */ 10f,
-            /* maxHunY= */ 0f,
+            /* hunMax = */ 0f,
         )
 
-        assertFalse(expandableViewState.headsUpIsVisible)
+        assertThat(expandableViewState.headsUpIsVisible).isFalse()
     }
 
     @Test
@@ -932,12 +928,12 @@
             expandableViewState,
             /* isShadeExpanded= */ false,
             /* mustStayOnScreen= */ true,
-            /* isViewEndVisible= */ true,
+            /* topVisible = */ true,
             /* viewEnd= */ 10f,
-            /* maxHunY= */ 1f,
+            /* hunMax = */ 1f,
         )
 
-        assertTrue(expandableViewState.headsUpIsVisible)
+        assertThat(expandableViewState.headsUpIsVisible).isTrue()
     }
 
     @Test
@@ -949,12 +945,12 @@
             expandableViewState,
             /* isShadeExpanded= */ true,
             /* mustStayOnScreen= */ false,
-            /* isViewEndVisible= */ true,
+            /* topVisible = */ true,
             /* viewEnd= */ 10f,
-            /* maxHunY= */ 1f,
+            /* hunMax = */ 1f,
         )
 
-        assertTrue(expandableViewState.headsUpIsVisible)
+        assertThat(expandableViewState.headsUpIsVisible).isTrue()
     }
 
     @Test
@@ -966,12 +962,12 @@
             expandableViewState,
             /* isShadeExpanded= */ true,
             /* mustStayOnScreen= */ true,
-            /* isViewEndVisible= */ false,
+            /* topVisible = */ false,
             /* viewEnd= */ 10f,
-            /* maxHunY= */ 1f,
+            /* hunMax = */ 1f,
         )
 
-        assertTrue(expandableViewState.headsUpIsVisible)
+        assertThat(expandableViewState.headsUpIsVisible).isTrue()
     }
 
     @Test
@@ -986,7 +982,7 @@
         )
 
         // qqs (10 + 0) < viewY (50)
-        assertEquals(50f, expandableViewState.yTranslation)
+        assertThat(expandableViewState.yTranslation).isEqualTo(50f)
     }
 
     @Test
@@ -1001,7 +997,7 @@
         )
 
         // qqs (10 + 0) > viewY (-10)
-        assertEquals(10f, expandableViewState.yTranslation)
+        assertThat(expandableViewState.yTranslation).isEqualTo(10f)
     }
 
     @Test
@@ -1019,7 +1015,7 @@
         // newTranslation = max(10, -100) = 10
         // distToRealY = 10 - (-100f) = 110
         // height = max(20 - 110, 10f)
-        assertEquals(10, expandableViewState.height)
+        assertThat(expandableViewState.height).isEqualTo(10)
     }
 
     @Test
@@ -1037,7 +1033,7 @@
         // newTranslation = max(10, 5) = 10
         // distToRealY = 10 - 5 = 5
         // height = max(20 - 5, 10) = 15
-        assertEquals(15, expandableViewState.height)
+        assertThat(expandableViewState.height).isEqualTo(15)
     }
 
     @Test
@@ -1047,9 +1043,9 @@
                 /* hostViewHeight= */ 100f,
                 /* stackY= */ 110f,
                 /* viewMaxHeight= */ 20f,
-                /* originalCornerRoundness= */ 0f,
+                /* originalCornerRadius = */ 0f,
             )
-        assertEquals(1f, currentRoundness)
+        assertThat(currentRoundness).isEqualTo(1f)
     }
 
     @Test
@@ -1059,9 +1055,9 @@
                 /* hostViewHeight= */ 100f,
                 /* stackY= */ 90f,
                 /* viewMaxHeight= */ 20f,
-                /* originalCornerRoundness= */ 0f,
+                /* originalCornerRadius = */ 0f,
             )
-        assertEquals(0.5f, currentRoundness)
+        assertThat(currentRoundness).isEqualTo(0.5f)
     }
 
     @Test
@@ -1071,9 +1067,9 @@
                 /* hostViewHeight= */ 100f,
                 /* stackY= */ 0f,
                 /* viewMaxHeight= */ 20f,
-                /* originalCornerRoundness= */ 0f,
+                /* originalCornerRadius = */ 0f,
             )
-        assertEquals(0f, currentRoundness)
+        assertThat(currentRoundness).isZero()
     }
 
     @Test
@@ -1083,9 +1079,9 @@
                 /* hostViewHeight= */ 100f,
                 /* stackY= */ 0f,
                 /* viewMaxHeight= */ 20f,
-                /* originalCornerRoundness= */ 1f,
+                /* originalCornerRadius = */ 1f,
             )
-        assertEquals(1f, currentRoundness)
+        assertThat(currentRoundness).isEqualTo(1f)
     }
 
     @Test
@@ -1105,13 +1101,14 @@
         stackScrollAlgorithm.updateChildZValue(
             /* i= */ 0,
             /* childrenOnTop= */ 0.0f,
-            /* StackScrollAlgorithmState= */ algorithmState,
+            /* algorithmState = */ algorithmState,
             /* ambientState= */ ambientState,
-            /* shouldElevateHun= */ true,
+            /* isTopHun = */ true,
         )
 
         // Then: full shadow would be applied
-        assertEquals(px(R.dimen.heads_up_pinned_elevation), childHunView.viewState.zTranslation)
+        assertThat(childHunView.viewState.zTranslation)
+            .isEqualTo(px(R.dimen.heads_up_pinned_elevation))
     }
 
     @Test
@@ -1133,9 +1130,9 @@
         stackScrollAlgorithm.updateChildZValue(
             /* i= */ 0,
             /* childrenOnTop= */ 0.0f,
-            /* StackScrollAlgorithmState= */ algorithmState,
+            /* algorithmState = */ algorithmState,
             /* ambientState= */ ambientState,
-            /* shouldElevateHun= */ true,
+            /* isTopHun = */ true,
         )
 
         // Then: HUN should have shadow, but not as full size
@@ -1166,13 +1163,13 @@
         stackScrollAlgorithm.updateChildZValue(
             /* i= */ 0,
             /* childrenOnTop= */ 0.0f,
-            /* StackScrollAlgorithmState= */ algorithmState,
+            /* algorithmState = */ algorithmState,
             /* ambientState= */ ambientState,
-            /* shouldElevateHun= */ true,
+            /* isTopHun = */ true,
         )
 
         // Then: HUN should not have shadow
-        assertEquals(0f, childHunView.viewState.zTranslation)
+        assertThat(childHunView.viewState.zTranslation).isZero()
     }
 
     @Test
@@ -1195,13 +1192,14 @@
         stackScrollAlgorithm.updateChildZValue(
             /* i= */ 0,
             /* childrenOnTop= */ 0.0f,
-            /* StackScrollAlgorithmState= */ algorithmState,
+            /* algorithmState = */ algorithmState,
             /* ambientState= */ ambientState,
-            /* shouldElevateHun= */ true,
+            /* isTopHun = */ true,
         )
 
         // Then: HUN should have full shadow
-        assertEquals(px(R.dimen.heads_up_pinned_elevation), childHunView.viewState.zTranslation)
+        assertThat(childHunView.viewState.zTranslation)
+            .isEqualTo(px(R.dimen.heads_up_pinned_elevation))
     }
 
     @Test
@@ -1225,9 +1223,9 @@
         stackScrollAlgorithm.updateChildZValue(
             /* i= */ 0,
             /* childrenOnTop= */ 0.0f,
-            /* StackScrollAlgorithmState= */ algorithmState,
+            /* algorithmState = */ algorithmState,
             /* ambientState= */ ambientState,
-            /* shouldElevateHun= */ true,
+            /* isTopHun = */ true,
         )
 
         // Then: HUN should have shadow, but not as full size
@@ -1251,7 +1249,7 @@
         stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
 
         // Then: ambientState.pulsingRow should still be pulsingNotificationView
-        assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+        assertThat(ambientState.isPulsingRow(pulsingNotificationView)).isTrue()
     }
 
     @Test
@@ -1268,7 +1266,7 @@
         stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
 
         // Then: ambientState.pulsingRow should record the pulsingNotificationView
-        assertTrue(ambientState.isPulsingRow(pulsingNotificationView))
+        assertThat(ambientState.isPulsingRow(pulsingNotificationView)).isTrue()
     }
 
     @Test
@@ -1287,7 +1285,7 @@
         stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState)
 
         // Then: ambientState.pulsingRow should be null
-        assertTrue(ambientState.isPulsingRow(null))
+        assertThat(ambientState.isPulsingRow(null)).isTrue()
     }
 
     @Test
@@ -1310,10 +1308,8 @@
         stackScrollAlgorithm.resetViewStates(ambientState, 0)
 
         // Then: pulsingNotificationView should show at full height
-        assertEquals(
-            stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView),
-            pulsingNotificationView.viewState.height,
-        )
+        assertThat(pulsingNotificationView.viewState.height)
+            .isEqualTo(stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView))
 
         // After: reset dozeAmount and expansionFraction
         ambientState.dozeAmount = 0f
@@ -1418,7 +1414,7 @@
                 yTranslation = ambientState.maxHeadsUpTranslation - height // move it to the max
             }
 
-        assertTrue(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+        assertThat(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState)).isTrue()
     }
 
     @Test
@@ -1431,7 +1427,8 @@
                     ambientState.maxHeadsUpTranslation - height - 1 // move it below the max
             }
 
-        assertFalse(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+        assertThat(stackScrollAlgorithm.shouldHunAppearFromBottom(ambientState, viewState))
+            .isFalse()
     }
 
     // endregion
@@ -1579,13 +1576,13 @@
 }
 
 private fun mockExpandableNotificationRow(): ExpandableNotificationRow {
-    return mock(ExpandableNotificationRow::class.java).apply {
+    return mock<ExpandableNotificationRow>().apply {
         whenever(viewState).thenReturn(ExpandableViewState())
     }
 }
 
 private fun mockFooterView(height: Int): FooterView {
-    return mock(FooterView::class.java).apply {
+    return mock<FooterView>().apply {
         whenever(viewState).thenReturn(FooterViewState())
         whenever(intrinsicHeight).thenReturn(height)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 778e822..7a51b2d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -1088,7 +1088,7 @@
 
     @Test
     @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
-    fun onMaxBoundsChanged_beforeStart_flagDisabled_listenerNotNotified() {
+    fun onMaxBoundsChanged_beforeStart_flagDisabled_listenerNotified() {
         // Start out with an existing configuration with bounds
         configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
         configurationController.onConfigurationChanged(configuration)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index f6d439a..5a77f3d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
 import android.os.ParcelUuid
-import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
 import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
@@ -25,91 +24,78 @@
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.MobileMappings
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
-import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.flags.fake
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryLogbufferName
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
-import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.fake
 import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.util.CarrierConfigTracker
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import java.util.UUID
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class MobileIconsInteractorTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
-
-    private lateinit var underTest: MobileIconsInteractor
-    private lateinit var connectivityRepository: FakeConnectivityRepository
-    private lateinit var connectionsRepository: FakeMobileConnectionsRepository
-    private val userSetupRepository = FakeUserSetupRepository()
-    private val mobileMappingsProxy = FakeMobileMappingsProxy()
-    private val flags =
-        FakeFeatureFlagsClassic().apply {
-            set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+    private val kosmos by lazy {
+        testKosmos().apply {
+            mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest"
+            mobileConnectionsRepository.fake.run {
+                setMobileConnectionRepositoryMap(
+                    mapOf(
+                        SUB_1_ID to CONNECTION_1,
+                        SUB_2_ID to CONNECTION_2,
+                        SUB_3_ID to CONNECTION_3,
+                        SUB_4_ID to CONNECTION_4,
+                    )
+                )
+                setActiveMobileDataSubscriptionId(SUB_1_ID)
+            }
+            featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
         }
+    }
 
-    private val testDispatcher = StandardTestDispatcher()
-    private val testScope = TestScope(testDispatcher)
+    // shortcut rename
+    private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
 
-    private val tableLogBuffer = logcatTableLogBuffer(kosmos, "MobileIconsInteractorTest")
+    private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
 
-    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        connectivityRepository = FakeConnectivityRepository()
-
-        connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer)
-        connectionsRepository.setMobileConnectionRepositoryMap(
-            mapOf(
-                SUB_1_ID to CONNECTION_1,
-                SUB_2_ID to CONNECTION_2,
-                SUB_3_ID to CONNECTION_3,
-                SUB_4_ID to CONNECTION_4,
-            )
+    private val Kosmos.underTest by Fixture {
+        MobileIconsInteractorImpl(
+            mobileConnectionsRepository,
+            carrierConfigTracker,
+            tableLogger = mock(),
+            connectivityRepository,
+            FakeUserSetupRepository(),
+            testScope.backgroundScope,
+            context,
+            featureFlagsClassic,
         )
-        connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
-
-        underTest =
-            MobileIconsInteractorImpl(
-                connectionsRepository,
-                carrierConfigTracker,
-                tableLogger = mock(),
-                connectivityRepository,
-                userSetupRepository,
-                testScope.backgroundScope,
-                context,
-                flags,
-            )
     }
 
     @Test
     fun filteredSubscriptions_default() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.filteredSubscriptions)
 
             assertThat(latest).isEqualTo(listOf<SubscriptionModel>())
@@ -118,7 +104,7 @@
     // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
     @Test
     fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
-        testScope.runTest {
+        kosmos.runTest {
             connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
 
@@ -129,7 +115,7 @@
 
     @Test
     fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
-        testScope.runTest {
+        kosmos.runTest {
             connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
 
             val latest by collectLastValue(underTest.filteredSubscriptions)
@@ -139,7 +125,7 @@
 
     @Test
     fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
-        testScope.runTest {
+        kosmos.runTest {
             connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
 
@@ -150,7 +136,7 @@
 
     @Test
     fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub1, sub2) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
@@ -167,7 +153,7 @@
 
     @Test
     fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub3, sub4) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
@@ -187,7 +173,7 @@
 
     @Test
     fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub3, sub4) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
@@ -207,7 +193,7 @@
 
     @Test
     fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -228,7 +214,7 @@
 
     @Test
     fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -249,7 +235,7 @@
 
     @Test
     fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -258,7 +244,7 @@
                 )
             connectionsRepository.setSubscriptions(listOf(sub1, sub3))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
-            connectivityRepository.vcnSubId.value = SUB_3_ID
+            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(false)
 
@@ -269,7 +255,7 @@
 
     @Test
     fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() =
-        testScope.runTest {
+        kosmos.runTest {
             val (sub1, sub3) =
                 createSubscriptionPair(
                     subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
@@ -278,7 +264,7 @@
                 )
             connectionsRepository.setSubscriptions(listOf(sub1, sub3))
             connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
-            connectivityRepository.vcnSubId.value = SUB_1_ID
+            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID
             whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
                 .thenReturn(false)
 
@@ -289,9 +275,9 @@
 
     @Test
     fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN the flag is false
-            flags.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+            featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
 
             // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
             val sub1 =
@@ -313,7 +299,7 @@
 
     @Test
     fun filteredSubscriptions_filtersOutProvisioningSubs() =
-        testScope.runTest {
+        kosmos.runTest {
             val sub1 =
                 SubscriptionModel(
                     subscriptionId = SUB_1_ID,
@@ -326,7 +312,7 @@
                     subscriptionId = SUB_2_ID,
                     isOpportunistic = false,
                     carrierName = "Carrier 2",
-                    profileClass = SubscriptionManager.PROFILE_CLASS_PROVISIONING,
+                    profileClass = PROFILE_CLASS_PROVISIONING,
                 )
 
             connectionsRepository.setSubscriptions(listOf(sub1, sub2))
@@ -339,7 +325,7 @@
     /** Note: I'm not sure if this will ever be the case, but we can test it at least */
     @Test
     fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
-        testScope.runTest {
+        kosmos.runTest {
             // This is a contrived test case, where the active subId is the one that would
             // also be filtered by opportunistic filtering.
 
@@ -376,7 +362,7 @@
 
     @Test
     fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
-        testScope.runTest {
+        kosmos.runTest {
             // Grouped filtering only happens when the list of subs is length 2. In this case
             // we'll show that filtering of provisioning subs happens before, and thus grouped
             // filtering happens even though the unfiltered list is length 3
@@ -406,7 +392,7 @@
 
     @Test
     fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() =
-        testScope.runTest {
+        kosmos.runTest {
             val notExclusivelyNonTerrestrialSub =
                 SubscriptionModel(
                     isExclusivelyNonTerrestrial = false,
@@ -424,7 +410,7 @@
 
     @Test
     fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() =
-        testScope.runTest {
+        kosmos.runTest {
             val exclusivelyNonTerrestrialSub =
                 SubscriptionModel(
                     isExclusivelyNonTerrestrial = true,
@@ -442,7 +428,7 @@
 
     @Test
     fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() =
-        testScope.runTest {
+        kosmos.runTest {
             val exclusivelyNonTerrestrialSub =
                 SubscriptionModel(
                     isExclusivelyNonTerrestrial = true,
@@ -476,7 +462,7 @@
 
     @Test
     fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() =
-        testScope.runTest {
+        kosmos.runTest {
             // Exclusively non-terrestrial sub
             val exclusivelyNonTerrestrialSub =
                 SubscriptionModel(
@@ -507,7 +493,7 @@
 
     @Test
     fun activeDataConnection_turnedOn() =
-        testScope.runTest {
+        kosmos.runTest {
             CONNECTION_1.setDataEnabled(true)
 
             val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
@@ -517,7 +503,7 @@
 
     @Test
     fun activeDataConnection_turnedOff() =
-        testScope.runTest {
+        kosmos.runTest {
             CONNECTION_1.setDataEnabled(true)
             val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
 
@@ -528,7 +514,7 @@
 
     @Test
     fun activeDataConnection_invalidSubId() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
 
             connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
@@ -539,7 +525,7 @@
 
     @Test
     fun failedConnection_default_validated_notFailed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -550,7 +536,7 @@
 
     @Test
     fun failedConnection_notDefault_notValidated_notFailed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = false
@@ -561,7 +547,7 @@
 
     @Test
     fun failedConnection_default_notValidated_failed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -572,7 +558,7 @@
 
     @Test
     fun failedConnection_carrierMergedDefault_notValidated_failed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.hasCarrierMergedConnection.value = true
@@ -584,7 +570,7 @@
     /** Regression test for b/275076959. */
     @Test
     fun failedConnection_dataSwitchInSameGroup_notFailed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -602,7 +588,7 @@
 
     @Test
     fun failedConnection_dataSwitchNotInSameGroup_isFailed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -618,7 +604,7 @@
 
     @Test
     fun alwaysShowDataRatIcon_configHasTrue() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
 
             val config = MobileMappings.Config()
@@ -630,7 +616,7 @@
 
     @Test
     fun alwaysShowDataRatIcon_configHasFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
 
             val config = MobileMappings.Config()
@@ -642,7 +628,7 @@
 
     @Test
     fun alwaysUseCdmaLevel_configHasTrue() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
 
             val config = MobileMappings.Config()
@@ -654,7 +640,7 @@
 
     @Test
     fun alwaysUseCdmaLevel_configHasFalse() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
 
             val config = MobileMappings.Config()
@@ -666,7 +652,7 @@
 
     @Test
     fun isSingleCarrier_zeroSubscriptions_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isSingleCarrier)
 
             connectionsRepository.setSubscriptions(emptyList())
@@ -676,7 +662,7 @@
 
     @Test
     fun isSingleCarrier_oneSubscription_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isSingleCarrier)
 
             connectionsRepository.setSubscriptions(listOf(SUB_1))
@@ -686,7 +672,7 @@
 
     @Test
     fun isSingleCarrier_twoSubscriptions_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isSingleCarrier)
 
             connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
@@ -696,7 +682,7 @@
 
     @Test
     fun isSingleCarrier_updates() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isSingleCarrier)
 
             connectionsRepository.setSubscriptions(listOf(SUB_1))
@@ -708,7 +694,7 @@
 
     @Test
     fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.mobileIsDefault)
 
             connectionsRepository.mobileIsDefault.value = false
@@ -719,7 +705,7 @@
 
     @Test
     fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.mobileIsDefault)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -731,7 +717,7 @@
     /** Regression test for b/272586234. */
     @Test
     fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.mobileIsDefault)
 
             connectionsRepository.mobileIsDefault.value = false
@@ -742,7 +728,7 @@
 
     @Test
     fun mobileIsDefault_updatesWhenRepoUpdates() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.mobileIsDefault)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -760,7 +746,7 @@
 
     @Test
     fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -774,17 +760,17 @@
 
             // After 1s, the force validation bit is still present, so the connection is not marked
             // as failed
-            advanceTimeBy(1000)
+            testScope.advanceTimeBy(1000)
             assertThat(latest).isFalse()
 
             // After 2s, the force validation expires so the connection updates to failed
-            advanceTimeBy(1001)
+            testScope.advanceTimeBy(1001)
             assertThat(latest).isTrue()
         }
 
     @Test
     fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             connectionsRepository.mobileIsDefault.value = true
@@ -798,7 +784,7 @@
 
     @Test
     fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
 
             // GIVEN the network starts validated
@@ -819,17 +805,17 @@
             // THEN the forced validation bit is still used...
             assertThat(latest).isFalse()
 
-            advanceTimeBy(1000)
+            testScope.advanceTimeBy(1000)
             assertThat(latest).isFalse()
 
             // ... but expires after 2s
-            advanceTimeBy(1001)
+            testScope.advanceTimeBy(1001)
             assertThat(latest).isTrue()
         }
 
     @Test
     fun dataSwitch_whileAlreadyForcingValidation_resetsClock() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDefaultConnectionFailed)
             connectionsRepository.mobileIsDefault.value = true
             connectionsRepository.defaultConnectionIsValidated.value = true
@@ -837,7 +823,7 @@
 
             connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
 
-            advanceTimeBy(1000)
+            testScope.advanceTimeBy(1000)
 
             // WHEN another change in same group event happens
             connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
@@ -847,37 +833,37 @@
             // THEN the forced validation remains for exactly 2 more seconds from now
 
             // 1.500s from second event
-            advanceTimeBy(1500)
+            testScope.advanceTimeBy(1500)
             assertThat(latest).isFalse()
 
             // 2.001s from the second event
-            advanceTimeBy(501)
+            testScope.advanceTimeBy(501)
             assertThat(latest).isTrue()
         }
 
     @Test
     fun isForceHidden_repoHasMobileHidden_true() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isForceHidden)
 
-            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
 
             assertThat(latest).isTrue()
         }
 
     @Test
     fun isForceHidden_repoDoesNotHaveMobileHidden_false() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isForceHidden)
 
-            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
 
             assertThat(latest).isFalse()
         }
 
     @Test
     fun iconInteractor_cachedPerSubId() =
-        testScope.runTest {
+        kosmos.runTest {
             val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
             val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
 
@@ -887,7 +873,7 @@
 
     @Test
     fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
-        testScope.runTest {
+        kosmos.runTest {
             val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
 
             connectionsRepository.isDeviceEmergencyCallCapable.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
index 46f822a..db24d4b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt
@@ -21,18 +21,18 @@
 import android.app.StatusBarManager.DISABLE_NONE
 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
 import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
-import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.test.runTest
-import org.junit.runner.RunWith;
+import org.junit.runner.RunWith
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index c4d2569..b9cdd06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -58,8 +58,8 @@
 import com.android.systemui.statusbar.data.model.StatusBarMode
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
 import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.events.data.repository.systemStatusEventAnimationRepository
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingIn
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingOut
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index d823bf5..4eef308 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -27,10 +27,14 @@
 import android.platform.test.annotations.EnableFlags
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.table.logcatTableLogBuffer
 import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
@@ -40,9 +44,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.user.data.repository.userRepository
 import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.time.fakeSystemClock
 import com.android.wifitrackerlib.HotspotNetworkEntry
 import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
@@ -53,31 +55,23 @@
 import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
 import com.android.wifitrackerlib.WifiPickerTracker
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.mockito.kotlin.any
-import org.mockito.kotlin.capture
+import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.times
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
-/**
- * Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
- *
- * Any new tests added here may also need to be added to [WifiRepositoryImplTest].
- */
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-class WifiRepositoryImplTest() : SysuiTestCase() {
-    private val kosmos = testKosmos()
+class WifiRepositoryImplTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val userRepository = kosmos.fakeUserRepository
 
     // Using lazy means that the class will only be constructed once it's fetched. Because the
@@ -108,13 +102,13 @@
 
     private val callbackCaptor = argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
 
-    private val dispatcher = StandardTestDispatcher()
-    private val testScope = TestScope(dispatcher)
+    private val dispatcher = kosmos.testDispatcher
+    private val testScope = kosmos.testScope
 
     @Before
     fun setUp() {
         userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER))
-        whenever(wifiPickerTrackerFactory.create(any(), any(), capture(callbackCaptor), any()))
+        whenever(wifiPickerTrackerFactory.create(any(), any(), callbackCaptor.capture(), any()))
             .thenReturn(wifiPickerTracker)
     }
 
@@ -122,7 +116,6 @@
     fun wifiPickerTrackerCreation_scansDisabled() =
         testScope.runTest {
             collectLastValue(underTest.wifiNetwork)
-            testScope.runCurrent()
 
             verify(wifiPickerTracker).disableScanning()
         }
@@ -1001,7 +994,6 @@
                 mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(false) }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
         }
@@ -1017,7 +1009,6 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
         }
@@ -1034,7 +1025,6 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
         }
@@ -1051,7 +1041,6 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
         }
@@ -1068,7 +1057,6 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
         }
@@ -1085,7 +1073,6 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
         }
@@ -1103,14 +1090,12 @@
                 }
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue()
 
             // WHEN the network is lost
             whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
             getCallback().onWifiEntriesChanged()
-            testScope.runCurrent()
 
             // THEN the isWifiConnected updates
             assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
@@ -1216,9 +1201,6 @@
             assertThat(latest).isEmpty()
         }
 
-    // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
-    // this needs to
-    // be updated to capture the argument instead so currentUserContext can be private.
     @Test
     @EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
     fun oneUserVerifyCreatingWifiPickerTracker_multiuserFlagEnabled() =
@@ -1230,16 +1212,16 @@
             )
 
             userRepository.setSelectedUserInfo(PRIMARY_USER)
-            runCurrent()
-            val currentUserContext by collectLastValue(underTest.selectedUserContext)
 
-            assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
-            verify(wifiPickerTrackerFactory).create(any(), any(), any(), any())
+            collectLastValue(underTest.wifiNetwork)
+
+            val contextCaptor = argumentCaptor<Context>()
+            verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+            // If the flag is on, verify that we use the context from #createContextAsUser and we
+            // do NOT use the top-level context
+            assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext)
         }
 
-    // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
-    // this needs to
-    // be updated to capture the argument instead so currentUserContext can be private.
     @Test
     @EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
     fun changeUserVerifyCreatingWifiPickerTracker_multiuserEnabled() =
@@ -1249,32 +1231,30 @@
                 UserHandle.of(PRIMARY_USER_ID),
                 primaryUserMockContext,
             )
-
-            runCurrent()
             userRepository.setSelectedUserInfo(PRIMARY_USER)
-            runCurrent()
-            val currentUserContext by collectLastValue(underTest.selectedUserContext)
 
-            assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
+            collectLastValue(underTest.wifiNetwork)
 
+            val contextCaptor = argumentCaptor<Context>()
+            verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+            assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext)
+
+            reset(wifiPickerTrackerFactory)
+
+            // WHEN we switch to a different user
             val otherUserMockContext = mock<Context>()
             mContext.prepareCreateContextAsUser(
                 UserHandle.of(ANOTHER_USER_ID),
                 otherUserMockContext,
             )
-
-            runCurrent()
             userRepository.setSelectedUserInfo(ANOTHER_USER)
-            runCurrent()
-            val otherUserContext by collectLastValue(underTest.selectedUserContext)
 
-            assertThat(otherUserContext).isEqualTo(otherUserMockContext)
-            verify(wifiPickerTrackerFactory, times(2)).create(any(), any(), any(), any())
+            // THEN we use the different user's context to create WifiPickerTracker
+            val newCaptor = argumentCaptor<Context>()
+            verify(wifiPickerTrackerFactory).create(newCaptor.capture(), any(), any(), any())
+            assertThat(newCaptor.firstValue).isEqualTo(otherUserMockContext)
         }
 
-    // TODO(b/371586248): This test currently require currentUserContext to be public for testing,
-    // this needs to
-    // be updated to capture the argument instead so currentUserContext can be private.
     @Test
     @DisableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
     fun changeUserVerifyCreatingWifiPickerTracker_multiuserDisabled() =
@@ -1285,36 +1265,39 @@
                 primaryUserMockContext,
             )
 
-            runCurrent()
             userRepository.setSelectedUserInfo(PRIMARY_USER)
-            runCurrent()
-            val currentUserContext by collectLastValue(underTest.selectedUserContext)
 
-            assertThat(currentUserContext).isEqualTo(primaryUserMockContext)
+            collectLastValue(underTest.wifiNetwork)
 
+            val contextCaptor = argumentCaptor<Context>()
+            verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any())
+            // If the flag is off, verify that we do NOT use the context from #createContextAsUser
+            // and we instead use the top-level context
+            assertThat(contextCaptor.firstValue).isNotEqualTo(primaryUserMockContext)
+            assertThat(contextCaptor.firstValue).isEqualTo(mContext)
+
+            reset(wifiPickerTrackerFactory)
+
+            // WHEN we switch to a different user
             val otherUserMockContext = mock<Context>()
             mContext.prepareCreateContextAsUser(
                 UserHandle.of(ANOTHER_USER_ID),
                 otherUserMockContext,
             )
-
-            runCurrent()
             userRepository.setSelectedUserInfo(ANOTHER_USER)
-            runCurrent()
 
-            verify(wifiPickerTrackerFactory, times(1)).create(any(), any(), any(), any())
+            // THEN we do NOT re-create WifiPickerTracker because the multiuser flag is off
+            verify(wifiPickerTrackerFactory, never()).create(any(), any(), any(), any())
         }
 
     private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
-        testScope.runCurrent()
-        return callbackCaptor.value
+        return callbackCaptor.firstValue
     }
 
     private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
-        testScope.runCurrent()
         val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
         verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
-        return callbackCaptor.value!!
+        return callbackCaptor.firstValue
     }
 
     private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry {
@@ -1325,10 +1308,9 @@
     }
 
     private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
-        testScope.runCurrent()
         val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
         verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
-        return callbackCaptor.value!!
+        return callbackCaptor.firstValue
     }
 
     private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 9a862fc..c5eed73 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -24,11 +24,19 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.plugins.statusbar.statusBarStateController
+import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
+import com.android.systemui.statusbar.phone.keyguardBypassController
 import com.android.systemui.statusbar.policy.HeadsUpManagerTestUtil.createFullScreenIntentEntry
+import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -48,6 +56,7 @@
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(NotificationThrottleHun.FLAG_NAME)
 class AvalancheControllerTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
 
     // For creating mocks
     @get:Rule var rule: MockitoRule = MockitoJUnit.rule()
@@ -61,7 +70,6 @@
     @Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
     private val mUiEventLoggerFake = UiEventLoggerFake()
     @Mock private lateinit var mHeadsUpManagerLogger: HeadsUpManagerLogger
-
     @Mock private lateinit var mBgHandler: Handler
 
     private val mLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer()))
@@ -76,26 +84,33 @@
         Mockito.`when`(
                 mAccessibilityMgr!!.getRecommendedTimeoutMillis(
                     ArgumentMatchers.anyInt(),
-                    ArgumentMatchers.anyInt()
+                    ArgumentMatchers.anyInt(),
                 )
             )
             .then { i: InvocationOnMock -> i.getArgument(0) }
 
         // Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
         // declaration, where mocks are null
-        mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake,
-                mHeadsUpManagerLogger, mBgHandler)
+        mAvalancheController =
+            AvalancheController(dumpManager, mUiEventLoggerFake, mHeadsUpManagerLogger, mBgHandler)
 
         testableHeadsUpManager =
             TestableHeadsUpManager(
                 mContext,
                 mLogger,
+                kosmos.statusBarStateController,
+                kosmos.keyguardBypassController,
+                GroupMembershipManagerImpl(),
+                kosmos.visualStabilityProvider,
+                kosmos.configurationController,
                 mExecutor,
                 mGlobalSettings,
                 mSystemClock,
                 mAccessibilityMgr,
                 mUiEventLoggerFake,
-                mAvalancheController
+                JavaAdapter(kosmos.testScope),
+                kosmos.shadeInteractor,
+                mAvalancheController,
             )
     }
 
@@ -270,7 +285,6 @@
         assertThat(mAvalancheController.headsUpEntryShowing).isEqualTo(nextEntry)
     }
 
-
     @Test
     fun testDelete_deleteSecondToLastEntry_showingEntryKeyBecomesPreviousHunKey() {
         mAvalancheController.previousHunKey = ""
@@ -305,7 +319,7 @@
         mAvalancheController.delete(showingEntry, runnableMock!!, "testLabel")
 
         // Next entry is shown
-        assertThat(mAvalancheController.previousHunKey).isEqualTo("");
+        assertThat(mAvalancheController.previousHunKey).isEqualTo("")
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 89aa670..abb3e6e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -35,6 +35,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Person;
@@ -49,15 +51,21 @@
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
 import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.FakeGlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,7 +81,10 @@
 @SmallTest
 @TestableLooper.RunWithLooper
 @RunWith(ParameterizedAndroidJunit4.class)
+// TODO(b/378142453): Merge this with BaseHeadsUpManagerTest.
 public class BaseHeadsUpManagerTest extends SysuiTestCase {
+    protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
 
@@ -85,6 +96,7 @@
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
     @Mock private Handler mBgHandler;
     @Mock private DumpManager dumpManager;
+    @Mock private ShadeInteractor mShadeInteractor;
     private AvalancheController mAvalancheController;
 
     @Mock private AccessibilityManagerWrapper mAccessibilityMgr;
@@ -108,8 +120,22 @@
     }
 
     private BaseHeadsUpManager createHeadsUpManager() {
-        return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
-                mSystemClock, mAccessibilityMgr, mUiEventLoggerFake, mAvalancheController);
+        return new TestableHeadsUpManager(
+                mContext,
+                mLogger,
+                mKosmos.getStatusBarStateController(),
+                mKosmos.getKeyguardBypassController(),
+                new GroupMembershipManagerImpl(),
+                mKosmos.getVisualStabilityProvider(),
+                mKosmos.getConfigurationController(),
+                mExecutor,
+                mGlobalSettings,
+                mSystemClock,
+                mAccessibilityMgr,
+                mUiEventLoggerFake,
+                new JavaAdapter(mKosmos.getTestScope()),
+                mShadeInteractor,
+                mAvalancheController);
     }
 
     private NotificationEntry createStickyEntry(int id) {
@@ -152,6 +178,8 @@
         super.SysuiSetup();
         mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake, mLogger,
                 mBgHandler);
+        when(mShadeInteractor.isAnyExpanded()).thenReturn(MutableStateFlow(true));
+        when(mKosmos.getKeyguardBypassController().getBypassEnabled()).thenReturn(false);
     }
 
     @Test
@@ -298,46 +326,6 @@
         verify(mLogger, times(1)).logNotificationActuallyRemoved(eq(notifEntry));
     }
 
-    @Test
-    public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry =
-                HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext);
-
-        // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
-        hum.showNotification(notifEntry);
-
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
-                notifEntry.getKey());
-        headsUpEntry.mWasUnpinned = false;
-
-        assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry));
-    }
-
-    @Test
-    public void testShouldHeadsUpBecomePinned_wasUnpinned_false() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry =
-                HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id = */ 0, mContext);
-
-        // Add notifEntry to ANM mAlertEntries map and make it unpinned
-        hum.showNotification(notifEntry);
-
-        final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = hum.getHeadsUpEntry(
-                notifEntry.getKey());
-        headsUpEntry.mWasUnpinned = true;
-
-        assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry));
-    }
-
-    @Test
-    public void testShouldHeadsUpBecomePinned_noFSI_false() {
-        final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
-
-        assertFalse(hum.shouldHeadsUpBecomePinned(entry));
-    }
-
 
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index 1915e8e..8ebdbaa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.statusbar.policy
 
-import android.content.Context
 import android.os.Handler
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
@@ -26,27 +25,19 @@
 import com.android.systemui.flags.andSceneContainer
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
-import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.FakeStatusBarStateController
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.testKosmos
-import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.kotlin.JavaAdapter
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.settings.GlobalSettings
-import com.android.systemui.util.time.SystemClock
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -78,7 +69,7 @@
 
     @Mock private lateinit var mVSProvider: VisualStabilityProvider
 
-    @Mock private lateinit var mStatusBarStateController: StatusBarStateController
+    val statusBarStateController = FakeStatusBarStateController()
 
     @Mock private lateinit var mBypassController: KeyguardBypassController
 
@@ -97,61 +88,16 @@
 
     @Mock private lateinit var mBgHandler: Handler
 
-    private class TestableHeadsUpManagerPhone(
-        context: Context,
-        headsUpManagerLogger: HeadsUpManagerLogger,
-        groupManager: GroupMembershipManager,
-        visualStabilityProvider: VisualStabilityProvider,
-        statusBarStateController: StatusBarStateController,
-        keyguardBypassController: KeyguardBypassController,
-        configurationController: ConfigurationController,
-        globalSettings: GlobalSettings,
-        systemClock: SystemClock,
-        executor: DelayableExecutor,
-        accessibilityManagerWrapper: AccessibilityManagerWrapper,
-        uiEventLogger: UiEventLogger,
-        javaAdapter: JavaAdapter,
-        shadeInteractor: ShadeInteractor,
-        avalancheController: AvalancheController
-    ) :
-        HeadsUpManagerPhone(
-            context,
-            headsUpManagerLogger,
-            statusBarStateController,
-            keyguardBypassController,
-            groupManager,
-            visualStabilityProvider,
-            configurationController,
-            mockExecutorHandler(executor),
-            globalSettings,
-            systemClock,
-            executor,
-            accessibilityManagerWrapper,
-            uiEventLogger,
-            javaAdapter,
-            shadeInteractor,
-            avalancheController
-        ) {
-        init {
-            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME
-            mAutoDismissTime = TEST_AUTO_DISMISS_TIME
-        }
-
-        /** Wrapper for [BaseHeadsUpManager.shouldHeadsUpBecomePinned] for testing */
-        fun shouldHeadsUpBecomePinnedWrapper(entry: NotificationEntry): Boolean {
-            return shouldHeadsUpBecomePinned(entry)
-        }
-    }
-
-    private fun createHeadsUpManagerPhone(): HeadsUpManagerPhone {
-        return TestableHeadsUpManagerPhone(
+    private fun createHeadsUpManagerPhone(): BaseHeadsUpManager {
+        return BaseHeadsUpManager(
             mContext,
             mHeadsUpManagerLogger,
+            statusBarStateController,
+            mBypassController,
             mGroupManager,
             mVSProvider,
-            mStatusBarStateController,
-            mBypassController,
             mConfigurationController,
+            mockExecutorHandler(mExecutor),
             mGlobalSettings,
             mSystemClock,
             mExecutor,
@@ -159,20 +105,22 @@
             mUiEventLogger,
             mJavaAdapter,
             mShadeInteractor,
-            mAvalancheController
+            mAvalancheController,
         )
     }
 
     @Before
     fun setUp() {
         whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(false))
+        whenever(mShadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false))
+        whenever(mBypassController.bypassEnabled).thenReturn(false)
         whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
         val accessibilityMgr =
             mDependency.injectMockDependency(AccessibilityManagerWrapper::class.java)
         whenever(
                 accessibilityMgr.getRecommendedTimeoutMillis(
                     ArgumentMatchers.anyInt(),
-                    ArgumentMatchers.anyInt()
+                    ArgumentMatchers.anyInt(),
                 )
             )
             .thenReturn(TEST_AUTO_DISMISS_TIME)
@@ -205,7 +153,7 @@
             hmp.removeNotification(
                 entry.key,
                 /* releaseImmediately= */ false,
-                /* reason= */ "swipe out"
+                /* reason= */ "swipe out",
             )
         Assert.assertTrue(removedImmediately)
         Assert.assertFalse(hmp.isHeadsUpEntry(entry.key))
@@ -245,6 +193,7 @@
         mSystemClock.advanceTime((TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2).toLong())
         Assert.assertTrue(hmp.isHeadsUpEntry(entry.key))
     }
+
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     fun testShowNotification_removeWhenReorderingAllowedTrue() {
@@ -253,7 +202,7 @@
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
         hmp.showNotification(notifEntry)
-        assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue();
+        assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
     }
 
     @Test
@@ -264,7 +213,7 @@
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
         hmp.showNotification(notifEntry)
-        assertThat(notifEntry.isSeenInShade).isTrue();
+        assertThat(notifEntry.isSeenInShade).isTrue()
     }
 
     @Test
@@ -275,197 +224,136 @@
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
         hmp.showNotification(notifEntry)
-        assertThat(notifEntry.isSeenInShade).isFalse();
+        assertThat(notifEntry.isSeenInShade).isFalse()
     }
 
     @Test
+    fun testShouldHeadsUpBecomePinned_noFSI_false() =
+        testScope.runTest {
+            val hum = createHeadsUpManagerPhone()
+            statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+            val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
+
+            Assert.assertFalse(hum.shouldHeadsUpBecomePinned(entry))
+        }
+
+    @Test
+    fun testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() =
+        testScope.runTest {
+            val hum = createHeadsUpManagerPhone()
+            statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+            val notifEntry =
+                HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
+
+            // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
+            hum.showNotification(notifEntry)
+
+            val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+            headsUpEntry!!.mWasUnpinned = false
+
+            Assert.assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry))
+        }
+
+    @Test
+    fun testShouldHeadsUpBecomePinned_wasUnpinned_false() =
+        testScope.runTest {
+            val hum = createHeadsUpManagerPhone()
+            statusBarStateController.setState(StatusBarState.KEYGUARD)
+
+            val notifEntry =
+                HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
+
+            // Add notifEntry to ANM mAlertEntries map and make it unpinned
+            hum.showNotification(notifEntry)
+
+            val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+            headsUpEntry!!.mWasUnpinned = true
+
+            Assert.assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry))
+        }
+
+    @Test
     fun shouldHeadsUpBecomePinned_shadeNotExpanded_true() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
             whenever(mShadeInteractor.isAnyFullyExpanded).thenReturn(MutableStateFlow(false))
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE)
             runCurrent()
 
             // THEN
-            Assert.assertTrue(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeLocked_false() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE_LOCKED)
             runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeUnknown_false() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(1207)
             runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_keyguardWithBypassOn_true() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
             whenever(mBypassController.bypassEnabled).thenReturn(true)
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.KEYGUARD)
             runCurrent()
 
             // THEN
-            Assert.assertTrue(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_keyguardWithBypassOff_false() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
             whenever(mBypassController.bypassEnabled).thenReturn(false)
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.KEYGUARD)
             runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeExpanded_false() =
         testScope.runTest {
             // GIVEN
-            val statusBarStateController = FakeStatusBarStateController()
             whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(true))
-            val hmp =
-                TestableHeadsUpManagerPhone(
-                    mContext,
-                    mHeadsUpManagerLogger,
-                    mGroupManager,
-                    mVSProvider,
-                    statusBarStateController,
-                    mBypassController,
-                    mConfigurationController,
-                    mGlobalSettings,
-                    mSystemClock,
-                    mExecutor,
-                    mAccessibilityManagerWrapper,
-                    mUiEventLogger,
-                    mJavaAdapter,
-                    mShadeInteractor,
-                    mAvalancheController
-                )
+            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE)
             runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinnedWrapper(entry))
+            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
         }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
index 3f33d2f..8593f6a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -21,9 +21,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.view.RotationPolicy;
@@ -37,7 +37,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @SmallTest
 public class RotationLockControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
index 3efabd7..59987f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
 import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
 
 import static org.mockito.Mockito.spy;
@@ -28,8 +27,14 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.SystemClock;
 
@@ -37,16 +42,39 @@
 
     private HeadsUpEntry mLastCreatedEntry;
 
-    TestableHeadsUpManager(Context context,
+    TestableHeadsUpManager(
+            Context context,
             HeadsUpManagerLogger logger,
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController bypassController,
+            GroupMembershipManager groupMembershipManager,
+            VisualStabilityProvider visualStabilityProvider,
+            ConfigurationController configurationController,
             DelayableExecutor executor,
             GlobalSettings globalSettings,
             SystemClock systemClock,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
             UiEventLogger uiEventLogger,
+            JavaAdapter javaAdapter,
+            ShadeInteractor shadeInteractor,
             AvalancheController avalancheController) {
-        super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
-                executor, accessibilityManagerWrapper, uiEventLogger, avalancheController);
+        super(
+                context,
+                logger,
+                statusBarStateController,
+                bypassController,
+                groupMembershipManager,
+                visualStabilityProvider,
+                configurationController,
+                mockExecutorHandler(executor),
+                globalSettings,
+                systemClock,
+                executor,
+                accessibilityManagerWrapper,
+                uiEventLogger,
+                javaAdapter,
+                shadeInteractor,
+                avalancheController);
 
         mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
         mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
@@ -61,11 +89,6 @@
         return mLastCreatedEntry;
     }
 
-    @Override
-    public int getContentFlag() {
-        return FLAG_CONTENT_VIEW_CONTRACTED;
-    }
-
     // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
     @Override
     public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
index 39836e2..e686ede 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
@@ -18,9 +18,13 @@
 
 package com.android.systemui.statusbar.policy.ui.dialog.viewmodel
 
+import android.app.AutomaticZenRule
 import android.content.Intent
 import android.content.applicationContext
 import android.provider.Settings
+import android.service.notification.SystemZenRules
+import android.service.notification.ZenModeConfig
+import android.service.notification.ZenModeConfig.ScheduleInfo
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.notification.modes.TestModeBuilder
@@ -35,6 +39,7 @@
 import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogEventLogger
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
+import java.util.Calendar
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.test.runCurrent
@@ -60,6 +65,9 @@
 
     private lateinit var underTest: ModesDialogViewModel
 
+    private lateinit var timeScheduleMode: ZenMode
+    private lateinit var timeScheduleInfo: ScheduleInfo
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -71,6 +79,21 @@
                 kosmos.mockModesDialogDelegate,
                 kosmos.mockModesDialogEventLogger,
             )
+
+        timeScheduleInfo = ZenModeConfig.ScheduleInfo()
+        timeScheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY)
+        timeScheduleInfo.startHour = 11
+        timeScheduleInfo.endHour = 15
+        timeScheduleMode =
+            TestModeBuilder()
+                .setPackage(SystemZenRules.PACKAGE_ANDROID)
+                .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME)
+                .setManualInvocationAllowed(true)
+                .setConditionId(ZenModeConfig.toScheduleConditionId(timeScheduleInfo))
+                .setTriggerDescription(
+                    SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, timeScheduleInfo)
+                )
+                .build()
     }
 
     @Test
@@ -325,17 +348,19 @@
                         .setTriggerDescription(null)
                         .setEnabled(false, /* byUser= */ false)
                         .build(),
+                    timeScheduleMode,
                 )
             )
             runCurrent()
 
-            assertThat(tiles!!).hasSize(6)
+            assertThat(tiles!!).hasSize(7)
             assertThat(tiles!![0].subtext).isEqualTo("When the going gets tough")
             assertThat(tiles!![1].subtext).isEqualTo("On • When in Rome")
             assertThat(tiles!![2].subtext).isEqualTo("Not set")
             assertThat(tiles!![3].subtext).isEqualTo("Off")
             assertThat(tiles!![4].subtext).isEqualTo("On")
             assertThat(tiles!![5].subtext).isEqualTo("Not set")
+            assertThat(tiles!![6].subtext).isEqualTo(timeScheduleMode.triggerDescription)
         }
 
     @Test
@@ -381,11 +406,12 @@
                         .setTriggerDescription(null)
                         .setEnabled(false, /* byUser= */ false)
                         .build(),
+                    timeScheduleMode,
                 )
             )
             runCurrent()
 
-            assertThat(tiles!!).hasSize(6)
+            assertThat(tiles!!).hasSize(7)
             with(tiles?.elementAt(0)!!) {
                 assertThat(this.stateDescription).isEqualTo("Off")
                 assertThat(this.subtextDescription).isEqualTo("When the going gets tough")
@@ -410,6 +436,12 @@
                 assertThat(this.stateDescription).isEqualTo("Off")
                 assertThat(this.subtextDescription).isEqualTo("Not set")
             }
+            with(tiles?.elementAt(6)!!) {
+                assertThat(this.stateDescription).isEqualTo("Off")
+                assertThat(this.subtextDescription)
+                    .isEqualTo(SystemZenRules.getDaysOfWeekFull(context, timeScheduleInfo)
+                    + ", " + SystemZenRules.getTimeSummary(context, timeScheduleInfo))
+            }
 
             // All tiles have the same long click info
             tiles!!.forEach { assertThat(it.onLongClickLabel).isEqualTo("Open settings") }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
new file mode 100644
index 0000000..7a9d017
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val fakeDisplayRepository = kosmos.displayRepository
+    private val testScope = kosmos.testScope
+
+    private val underTest by lazy { kosmos.multiDisplayStatusBarWindowControllerStore }
+
+    @Before
+    fun start() {
+        underTest.start()
+    }
+
+    @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+    @Test
+    fun beforeDisplayRemoved_doesNotStopInstances() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            verify(instance, never()).stop()
+        }
+
+    @Test
+    fun displayRemoved_stopsInstance() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+            verify(instance).stop()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
index 6e66287..61c7193 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt
@@ -17,12 +17,17 @@
 
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
+import android.view.fakeWindowManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.fragments.fragmentService
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.core.StatusBarRootModernization
 import com.android.systemui.statusbar.policy.statusBarConfigurationController
 import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.any
@@ -37,6 +42,9 @@
         testKosmos().also { it.statusBarWindowViewInflater = it.fakeStatusBarWindowViewInflater }
 
     private val underTest = kosmos.statusBarWindowControllerImpl
+    private val fakeExecutor = kosmos.fakeExecutor
+    private val fakeWindowManager = kosmos.fakeWindowManager
+    private val mockFragmentService = kosmos.fragmentService
     private val fakeStatusBarWindowViewInflater = kosmos.fakeStatusBarWindowViewInflater
     private val statusBarConfigurationController = kosmos.statusBarConfigurationController
 
@@ -59,4 +67,64 @@
 
         verify(mockWindowView, never()).setStatusBarConfigurationController(any())
     }
+
+    @Test
+    @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME)
+    fun stop_statusBarModernizationFlagEnabled_doesNotRemoveFragment() {
+        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+        underTest.stop()
+        fakeExecutor.runAllReady()
+
+        verify(mockFragmentService, never()).removeAndDestroy(windowView)
+    }
+
+    @Test
+    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
+    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+    fun stop_statusBarModernizationFlagDisabled_removesFragment() {
+        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+        underTest.stop()
+        fakeExecutor.runAllReady()
+
+        verify(mockFragmentService).removeAndDestroy(windowView)
+    }
+
+    @Test
+    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
+    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+    fun stop_statusBarModernizationFlagDisabled_removesFragmentOnExecutor() {
+        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+        underTest.stop()
+
+        verify(mockFragmentService, never()).removeAndDestroy(windowView)
+        fakeExecutor.runAllReady()
+        verify(mockFragmentService).removeAndDestroy(windowView)
+    }
+
+    @Test
+    @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+    fun stop_removesWindowViewFromWindowManager() {
+        underTest.attach()
+        underTest.stop()
+
+        assertThat(fakeWindowManager.addedViews).isEmpty()
+    }
+
+    @Test(expected = IllegalStateException::class)
+    @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+    fun stop_connectedDisplaysFlagDisabled_crashes() {
+        underTest.stop()
+    }
+
+    @Test
+    fun attach_windowViewAddedToWindowManager() {
+        val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first()
+
+        underTest.attach()
+
+        assertThat(fakeWindowManager.addedViews.keys).containsExactly(windowView)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
index 9592b28..798380a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
@@ -18,8 +18,8 @@
 
 import android.hardware.BatteryState
 import android.hardware.input.InputManager
-import android.testing.AndroidTestingRunner
 import android.view.InputDevice
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
@@ -35,7 +35,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class StylusUsiPowerStartableTest : SysuiTestCase() {
     @Mock lateinit var inputManager: InputManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt
index 01dd60a..4351d28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/TestableAlertDialogTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/TestableAlertDialogTest.kt
@@ -21,8 +21,8 @@
 import android.content.DialogInterface.BUTTON_NEGATIVE
 import android.content.DialogInterface.BUTTON_NEUTRAL
 import android.content.DialogInterface.BUTTON_POSITIVE
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.any
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class TestableAlertDialogTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
index 1ff9548..c6bfb35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
@@ -21,9 +21,9 @@
 import static org.mockito.Mockito.verify;
 
 import android.animation.Animator;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@
 
 @SmallTest
 @TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class KeepAwakeAnimationListenerTest extends SysuiTestCase {
     @Mock WakeLock mWakeLock;
     KeepAwakeAnimationListener mKeepAwakeAnimationListener;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 89da465..fb9e96c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -139,7 +139,9 @@
 
     /** Message buffer for large clock rendering */
     val largeClockMessageBuffer: MessageBuffer,
-)
+) {
+    constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {}
+}
 
 data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float)
 
diff --git a/packages/SystemUI/pods/Android.bp b/packages/SystemUI/pods/Android.bp
new file mode 100644
index 0000000..e45f317
--- /dev/null
+++ b/packages/SystemUI/pods/Android.bp
@@ -0,0 +1,22 @@
+//
+// 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 {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+    // The package default_visibility specified here is inherited to subpackages that do not
+    // specify default_visibility:
+    default_visibility: ["//visibility:private"],
+}
diff --git a/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp
new file mode 100644
index 0000000..df90be8
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp
@@ -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.
+//
+
+soong_namespace {
+}
+
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+    name: "api",
+    srcs: [
+        "**/*.java",
+        "**/*.kt",
+    ],
+    libs: [
+        "jsr330",
+    ],
+    visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java b/packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp
new file mode 100644
index 0000000..f047848
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+soong_namespace {
+}
+
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+    name: "impl",
+    srcs: ["*.kt"],
+    libs: [
+        "jsr330",
+        "dagger2",
+        "SystemUICommon",
+        "kotlinx_coroutines",
+    ],
+    static_libs: [
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:impl",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain:impl",
+    ],
+    visibility: ["//frameworks/base/packages/SystemUI"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
index e863949..c20e368 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.retail.dagger
+package com.android.systemui.retail
 
 import com.android.systemui.retail.data.repository.RetailModeRepository
-import com.android.systemui.retail.data.repository.RetailModeSettingsRepository
+import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository
 import com.android.systemui.retail.domain.interactor.RetailModeInteractor
-import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl
+import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl
 import dagger.Binds
 import dagger.Module
 
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp
new file mode 100644
index 0000000..f148a7c
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp
@@ -0,0 +1,55 @@
+//
+// 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.
+//
+
+soong_namespace {
+}
+
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+    name: "api",
+    srcs: ["repository/*.kt"],
+    libs: [
+        "kotlinx_coroutines",
+    ],
+    visibility: [
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain",
+    ],
+}
+
+java_library {
+    name: "impl",
+    srcs: ["repository/impl/*.kt"],
+    libs: [
+        "jsr330",
+        "kotlinx_coroutines",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api",
+        "SystemUICommon",
+    ],
+    static_libs: [
+        "api",
+    ],
+    visibility: [
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain",
+    ],
+}
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt
new file mode 100644
index 0000000..c9eac25
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.retail.data.repository
+
+import kotlinx.coroutines.flow.StateFlow
+
+/** Repository to track if the device is in Retail mode */
+interface RetailModeRepository {
+    /** Flow of whether the device is currently in retail mode. */
+    val retailMode: StateFlow<Boolean>
+
+    /** Last value of whether the device is in retail mode. */
+    val inRetailMode: Boolean
+        get() = retailMode.value
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
index 09fd7df..8955263 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.retail.data.repository
+package com.android.systemui.retail.data.repository.impl
 
 import android.database.ContentObserver
 import android.provider.Settings
@@ -22,6 +22,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.retail.data.repository.RetailModeRepository
 import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -34,16 +35,6 @@
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
 
-/** Repository to track if the device is in Retail mode */
-interface RetailModeRepository {
-    /** Flow of whether the device is currently in retail mode. */
-    val retailMode: StateFlow<Boolean>
-
-    /** Last value of whether the device is in retail mode. */
-    val inRetailMode: Boolean
-        get() = retailMode.value
-}
-
 /**
  * Tracks [Settings.Global.DEVICE_DEMO_MODE].
  *
diff --git a/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp
new file mode 100644
index 0000000..787861c
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+//
+
+soong_namespace {
+}
+
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+    name: "api",
+    srcs: ["interactor/*.kt"],
+    visibility: [
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+    ],
+}
+
+java_library {
+    name: "impl",
+    srcs: ["interactor/impl/*.kt"],
+    libs: [
+        "jsr330",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:api",
+    ],
+    static_libs: [
+        "api",
+    ],
+    visibility: [
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail",
+    ],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
copy to packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
index eea452c..748e34d 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -16,22 +16,8 @@
 
 package com.android.systemui.retail.domain.interactor
 
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.retail.data.repository.RetailModeRepository
-import javax.inject.Inject
-
 /** Interactor to determine if the device is currently in retail mode */
 interface RetailModeInteractor {
     /** Whether the device is currently in retail mode */
     val isInRetailMode: Boolean
 }
-
-@SysUISingleton
-class RetailModeInteractorImpl
-@Inject
-constructor(
-    private val repository: RetailModeRepository,
-) : RetailModeInteractor {
-    override val isInRetailMode: Boolean
-        get() = repository.inRetailMode
-}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
similarity index 79%
rename from packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
index eea452c..8dbe562 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
@@ -14,18 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.retail.domain.interactor
+package com.android.systemui.retail.domain.interactor.impl
 
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.retail.data.repository.RetailModeRepository
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor
 import javax.inject.Inject
 
-/** Interactor to determine if the device is currently in retail mode */
-interface RetailModeInteractor {
-    /** Whether the device is currently in retail mode */
-    val isInRetailMode: Boolean
-}
-
 @SysUISingleton
 class RetailModeInteractorImpl
 @Inject
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp
new file mode 100644
index 0000000..1aa7729
--- /dev/null
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+
+soong_namespace {
+}
+
+package {
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+    name: "api",
+    srcs: [
+        "*.java",
+        "*.kt",
+    ],
+    libs: [
+        "//frameworks/libs/systemui:tracinglib-platform",
+        "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api",
+        "SystemUICommon",
+        "androidx.annotation_annotation",
+        "kotlinx_coroutines_android",
+        "jsr330",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+    visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 7fcabe4..d68501f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 import android.provider.Settings;
 
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
 import kotlinx.coroutines.CoroutineDispatcher;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
index c296481..211a6f4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -21,7 +21,7 @@
 import android.net.Uri;
 import android.provider.Settings;
 
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
 import kotlinx.coroutines.CoroutineDispatcher;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
index e13981d..5632a36 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.util.kotlin;
+package com.android.systemui.util.settings;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
index e670b2c..1b3f74e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -21,7 +21,7 @@
 import android.net.Uri;
 import android.provider.Settings;
 
-import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
+import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
 import kotlinx.coroutines.CoroutineDispatcher;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
rename to packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml
similarity index 94%
rename from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml
rename to packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml
index c83b6d3..dfefb9d 100644
--- a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml
+++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml
@@ -14,7 +14,8 @@
     limitations under the License.
 -->
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:paddingMode="stack">
     <item>
@@ -30,8 +31,8 @@
         android:end="20dp"
         android:gravity="end|center_vertical">
         <vector
-            android:width="@dimen/hearing_devices_preset_spinner_arrow_size"
-            android:height="@dimen/hearing_devices_preset_spinner_arrow_size"
+            android:width="@dimen/hearing_devices_preset_spinner_icon_size"
+            android:height="@dimen/hearing_devices_preset_spinner_icon_size"
             android:viewportWidth="24"
             android:viewportHeight="24"
             android:tint="?androidprv:attr/colorControlNormal">
diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml
rename to packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml
diff --git a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml
similarity index 66%
rename from packages/SystemUI/res/drawable/volume_dialog_spacer.xml
rename to packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml
index 3c60784..c708d22 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
+++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
     Copyright (C) 2024 The Android Open Source Project
 
     Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,11 +14,9 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <size
-        android:width="@dimen/volume_dialog_spacing"
-        android:height="@dimen/volume_dialog_spacing" />
-    <solid android:color="@color/transparent" />
-</shape>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/settingslib_switch_bar_bg_on"
+    android:insetTop="8dp"
+    android:insetBottom="8dp"
+    android:insetLeft="11dp"
+    android:insetRight="11dp" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_check.xml b/packages/SystemUI/res/drawable/ic_check.xml
new file mode 100644
index 0000000..80707d8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_check.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:pathData="M0 0h24v24H0z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_background_top.xml b/packages/SystemUI/res/drawable/volume_background_top.xml
index 75849be..132572a 100644
--- a/packages/SystemUI/res/drawable/volume_background_top.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top.xml
@@ -17,7 +17,6 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <item>
         <shape>
-            <size android:width="@dimen/volume_dialog_width" />
             <solid android:color="?androidprv:attr/materialColorSurface" />
             <corners android:topLeftRadius="@dimen/volume_dialog_background_corner_radius"
                 android:topRightRadius="@dimen/volume_dialog_background_corner_radius"/>
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index b9314c7..124aec6a 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -27,8 +27,8 @@
 
     <ImageView
         android:id="@+id/bluetooth_device_icon"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
@@ -36,8 +36,8 @@
 
     <TextView
         android:layout_width="0dp"
+        android:layout_height="wrap_content"
         android:id="@+id/bluetooth_device_name"
-        style="@style/BluetoothTileDialog.DeviceName"
         android:textDirection="locale"
         android:textAlignment="gravity"
         android:paddingStart="20dp"
@@ -54,8 +54,8 @@
 
     <TextView
         android:layout_width="0dp"
+        android:layout_height="wrap_content"
         android:id="@+id/bluetooth_device_summary"
-        style="@style/BluetoothTileDialog.DeviceSummary"
         android:paddingStart="20dp"
         android:paddingEnd="10dp"
         android:paddingBottom="15dp"
@@ -65,7 +65,8 @@
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
         app:layout_constraintEnd_toStartOf="@+id/guideline"
         app:layout_constraintBottom_toBottomOf="parent"
-        android:gravity="center_vertical" />
+        android:gravity="center_vertical"
+        android:textSize="14sp" />
 
     <androidx.constraintlayout.widget.Guideline
         android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index b4eaa40..1f93717 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -32,7 +32,7 @@
         android:ellipsize="end"
         android:gravity="center_vertical|center_horizontal"
         android:text="@string/quick_settings_bluetooth_label"
-        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
         android:textSize="24sp"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
@@ -49,7 +49,8 @@
         android:gravity="center_vertical|center_horizontal"
         android:maxLines="2"
         android:text="@string/quick_settings_bluetooth_tile_subtitle"
-        android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+        android:textSize="14sp"
+        android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />
@@ -105,7 +106,7 @@
                 android:paddingStart="36dp"
                 android:text="@string/turn_on_bluetooth"
                 android:clickable="false"
-                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:textSize="16sp"
                 app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
                 app:layout_constraintStart_toStartOf="parent"
@@ -146,7 +147,7 @@
                 android:paddingEnd="15dp"
                 android:paddingStart="36dp"
                 android:clickable="false"
-                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:textSize="16sp"
                 app:layout_constraintEnd_toStartOf="@+id/bluetooth_auto_on_toggle"
                 app:layout_constraintStart_toStartOf="parent"
@@ -187,7 +188,8 @@
                 android:layout_marginTop="20dp"
                 android:paddingStart="36dp"
                 android:paddingEnd="40dp"
-                android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+                android:textSize="14sp"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toBottomOf="@id/bluetooth_auto_on_toggle_info_icon" />
@@ -204,7 +206,7 @@
                 android:id="@+id/see_all_button"
                 style="@style/BluetoothTileDialog.Device"
                 android:paddingEnd="0dp"
-                android:paddingStart="20dp"
+                android:paddingStart="26dp"
                 android:background="@drawable/bluetooth_tile_dialog_bg_off"
                 android:layout_width="0dp"
                 android:layout_height="64dp"
@@ -214,11 +216,11 @@
                 app:layout_constraintTop_toBottomOf="@+id/device_list"
                 app:layout_constraintBottom_toTopOf="@+id/pair_new_device_button"
                 android:drawableStart="@drawable/ic_arrow_forward"
-                android:drawablePadding="20dp"
+                android:drawablePadding="26dp"
                 android:drawableTint="?android:attr/textColorPrimary"
                 android:text="@string/see_all_bluetooth_devices"
                 android:textSize="14sp"
-                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:textDirection="locale"
                 android:textAlignment="viewStart"
                 android:maxLines="1"
@@ -229,7 +231,7 @@
                 android:id="@+id/pair_new_device_button"
                 style="@style/BluetoothTileDialog.Device"
                 android:paddingEnd="0dp"
-                android:paddingStart="20dp"
+                android:paddingStart="26dp"
                 android:background="@drawable/bluetooth_tile_dialog_bg_off"
                 android:layout_width="0dp"
                 android:layout_height="64dp"
@@ -238,11 +240,11 @@
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintTop_toBottomOf="@+id/see_all_button"
                 android:drawableStart="@drawable/ic_add"
-                android:drawablePadding="20dp"
+                android:drawablePadding="26dp"
                 android:drawableTint="?android:attr/textColorPrimary"
                 android:text="@string/pair_new_bluetooth_devices"
                 android:textSize="14sp"
-                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:textDirection="locale"
                 android:textAlignment="viewStart"
                 android:maxLines="1"
@@ -259,6 +261,7 @@
             <Button
                 android:id="@+id/audio_sharing_button"
                 style="@style/BluetoothTileDialog.AudioSharingButton"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="9dp"
@@ -282,6 +285,7 @@
             <Button
                 android:id="@+id/done_button"
                 style="@style/Widget.Dialog.Button"
+                android:textAppearance="@style/TextAppearance.BluetoothTileDialog"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginTop="9dp"
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml b/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
deleted file mode 100644
index 17c0222..0000000
--- a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml
+++ /dev/null
@@ -1,26 +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.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/hearing_devices_preset_option_text"
-    style="?android:attr/spinnerDropDownItemStyle"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="@dimen/hearing_devices_preset_spinner_height"
-    android:paddingStart="@dimen/hearing_devices_preset_spinner_text_padding_start"
-    android:gravity="center_vertical"
-    android:textDirection="locale"
-    android:ellipsize="end" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml b/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
deleted file mode 100644
index d512e7c..0000000
--- a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml
+++ /dev/null
@@ -1,48 +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.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="@dimen/hearing_devices_preset_spinner_height"
-    android:paddingStart="@dimen/hearing_devices_preset_spinner_text_padding_start"
-    android:paddingTop="@dimen/hearing_devices_preset_spinner_text_padding_vertical"
-    android:paddingBottom="@dimen/hearing_devices_preset_spinner_text_padding_vertical"
-    android:orientation="vertical">
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:textAppearance="@style/TextAppearance.Dialog.Title"
-        android:lineSpacingExtra="6dp"
-        android:text="@string/hearing_devices_preset_label"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        android:textSize="14sp"
-        android:gravity="center_vertical"
-        android:textDirection="locale"
-        android:layout_weight="1" />
-    <TextView
-        android:id="@+id/hearing_devices_preset_option_text"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:textAppearance="@style/TextAppearance.Dialog.Body"
-        android:lineSpacingExtra="6dp"
-        android:gravity="center_vertical"
-        android:ellipsize="end"
-        android:maxLines="1"
-        android:textDirection="locale"
-        android:layout_weight="1" />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml
new file mode 100644
index 0000000..70f2cd5
--- /dev/null
+++ b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml
@@ -0,0 +1,45 @@
+<!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/bluetooth_dialog_device_height"
+    android:paddingStart="@dimen/hearing_devices_preset_spinner_padding"
+    android:paddingEnd="@dimen/hearing_devices_preset_spinner_padding"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/hearing_devices_spinner_check_icon"
+        android:layout_width="@dimen/hearing_devices_preset_spinner_icon_size"
+        android:layout_height="@dimen/hearing_devices_preset_spinner_icon_size"
+        android:layout_gravity="center_vertical"
+        android:layout_marginEnd="@dimen/hearing_devices_layout_margin"
+        android:tint="?androidprv:attr/materialColorOnPrimaryContainer"
+        android:src="@drawable/ic_check"
+        android:contentDescription="@string/hearing_devices_spinner_item_selected"/>
+    <TextView
+        android:id="@+id/hearing_devices_spinner_text"
+        style="?android:attr/spinnerDropDownItemStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:textDirection="locale"
+        android:paddingStart="0dp"
+        android:maxLines="1"
+        android:ellipsize="end" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml
new file mode 100644
index 0000000..7574244
--- /dev/null
+++ b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml
@@ -0,0 +1,32 @@
+<!--
+    Copyright (C) 2024 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/bluetooth_dialog_device_height"
+    android:paddingStart="@dimen/hearing_devices_preset_spinner_padding"
+    android:paddingEnd="@dimen/hearing_devices_preset_spinner_padding">
+    <TextView
+        android:id="@+id/hearing_devices_spinner_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/TextAppearance.Dialog.Body"
+        android:layout_gravity="center_vertical"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:textDirection="locale" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
index 80692f9..bf04a6f 100644
--- a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml
@@ -28,50 +28,16 @@
         android:layout_height="wrap_content"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/preset_spinner" />
-
-    <Spinner
-        android:id="@+id/preset_spinner"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/hearing_devices_layout_margin"
-        android:minHeight="@dimen/hearing_devices_preset_spinner_height"
-        android:gravity="center_vertical"
-        android:background="@drawable/hearing_devices_preset_spinner_background"
-        android:popupBackground="@drawable/hearing_devices_preset_spinner_popup_background"
-        android:dropDownVerticalOffset="@dimen/hearing_devices_preset_spinner_height"
-        android:dropDownWidth="match_parent"
-        android:paddingStart="0dp"
-        android:paddingEnd="0dp"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/device_list"
-        app:layout_constraintBottom_toTopOf="@id/pair_new_device_button"
-        android:longClickable="false"
-        android:visibility="gone"/>
-
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/device_function_barrier"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierAllowsGoneWidgets="false"
-        app:barrierDirection="bottom"
-        app:constraint_referenced_ids="device_list,preset_spinner" />
+        app:layout_constraintEnd_toEndOf="parent" />
 
     <Button
         android:id="@+id/pair_new_device_button"
         style="@style/BluetoothTileDialog.Device"
-        android:paddingEnd="0dp"
-        android:paddingStart="20dp"
-        android:background="@drawable/bluetooth_tile_dialog_bg_off"
-        android:layout_width="0dp"
-        android:layout_height="64dp"
-        android:contentDescription="@string/accessibility_hearing_device_pair_new_device"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/device_function_barrier"
+        app:layout_constraintTop_toBottomOf="@id/device_list"
+        android:layout_height="@dimen/bluetooth_dialog_device_height"
+        android:contentDescription="@string/accessibility_hearing_device_pair_new_device"
         android:drawableStart="@drawable/ic_add"
         android:drawablePadding="20dp"
         android:drawableTint="?android:attr/textColorPrimary"
@@ -81,26 +47,75 @@
         android:textDirection="locale"
         android:textAlignment="viewStart"
         android:maxLines="1"
-        android:ellipsize="end" />
-
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/device_barrier"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierAllowsGoneWidgets="false"
-        app:barrierDirection="bottom"
-        app:constraint_referenced_ids="device_function_barrier, pair_new_device_button" />
+        android:ellipsize="end"
+        android:background="@drawable/bluetooth_tile_dialog_bg_off" />
 
     <LinearLayout
-        android:id="@+id/related_tools_container"
+        android:id="@+id/preset_layout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
-        android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
-        android:layout_marginTop="@dimen/hearing_devices_layout_margin"
-        android:orientation="horizontal"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/device_barrier" />
+        app:layout_constraintTop_toBottomOf="@id/pair_new_device_button"
+        android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/preset_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+            android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+            android:paddingStart="@dimen/hearing_devices_small_title_padding_horizontal"
+            android:text="@string/hearing_devices_preset_label"
+            android:textAppearance="@style/TextAppearance.Dialog.Title"
+            android:textSize="14sp"
+            android:gravity="center_vertical"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+            android:textDirection="locale"/>
+        <Spinner
+            android:id="@+id/preset_spinner"
+            style="@style/BluetoothTileDialog.Device"
+            android:layout_height="@dimen/bluetooth_dialog_device_height"
+            android:layout_marginTop="4dp"
+            android:paddingStart="0dp"
+            android:paddingEnd="0dp"
+            android:background="@drawable/hearing_devices_spinner_background"
+            android:popupBackground="@drawable/hearing_devices_spinner_popup_background"
+            android:dropDownWidth="match_parent"
+            android:longClickable="false"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/tools_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/preset_layout"
+        android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+        android:orientation="vertical">
+        <TextView
+            android:id="@+id/tools_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+            android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+            android:paddingStart="@dimen/hearing_devices_small_title_padding_horizontal"
+            android:text="@string/hearing_devices_tools_label"
+            android:textAppearance="@style/TextAppearance.Dialog.Title"
+            android:textSize="14sp"
+            android:gravity="center_vertical"
+            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+            android:textDirection="locale"/>
+        <LinearLayout
+            android:id="@+id/tools_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin"
+            android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin"
+            android:layout_marginTop="4dp"
+            android:orientation="horizontal"/>
+    </LinearLayout>
+
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hearing_tool_item.xml b/packages/SystemUI/res/layout/hearing_tool_item.xml
index f5baf2a..da9178b 100644
--- a/packages/SystemUI/res/layout/hearing_tool_item.xml
+++ b/packages/SystemUI/res/layout/hearing_tool_item.xml
@@ -46,7 +46,7 @@
         android:textAlignment="center"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/hearing_devices_layout_margin"
+        android:layout_marginTop="4dp"
         android:ellipsize="end"
         android:textSize="12sp"
         android:maxLines="3"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
index 7c59aad..71c77a5 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml
@@ -44,13 +44,13 @@
             android:layout_height="wrap_content">
 
             <com.android.systemui.statusbar.notification.row.FooterViewButton
-                android:id="@+id/settings_button"
+                android:id="@+id/history_button"
                 style="@style/TextAppearance.NotificationFooterButtonRedesign"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
                 android:background="@drawable/notif_footer_btn_background"
-                android:contentDescription="@string/notification_settings_button_description"
-                android:drawableStart="@drawable/notif_footer_btn_settings"
+                android:contentDescription="@string/notification_history_button_description"
+                android:drawableStart="@drawable/notif_footer_btn_history"
                 android:focusable="true"
                 app:layout_constraintStart_toStartOf="parent" />
 
@@ -64,17 +64,17 @@
                 android:contentDescription="@string/accessibility_clear_all"
                 android:focusable="true"
                 android:text="@string/clear_all_notifications_text"
-                app:layout_constraintEnd_toStartOf="@id/history_button"
-                app:layout_constraintStart_toEndOf="@id/settings_button" />
+                app:layout_constraintEnd_toStartOf="@id/settings_button"
+                app:layout_constraintStart_toEndOf="@id/history_button" />
 
             <com.android.systemui.statusbar.notification.row.FooterViewButton
-                android:id="@+id/history_button"
+                android:id="@+id/settings_button"
                 style="@style/TextAppearance.NotificationFooterButtonRedesign"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
                 android:background="@drawable/notif_footer_btn_background"
-                android:contentDescription="@string/notification_history_button_description"
-                android:drawableStart="@drawable/notif_footer_btn_history"
+                android:contentDescription="@string/notification_settings_button_description"
+                android:drawableStart="@drawable/notif_footer_btn_settings"
                 android:focusable="true"
                 app:layout_constraintEnd_toEndOf="parent" />
         </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index f187ce6..694357d 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,58 +13,70 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.motion.widget.MotionLayout 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"
     android:id="@+id/volume_dialog_root"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    app:layoutDescription="@xml/volume_dialog_scene">
 
-    <LinearLayout
-        android:id="@+id/volume_dialog_container"
+    <View
+        android:id="@+id/volume_dialog_background"
+        android:layout_width="@dimen/volume_dialog_width"
+        android:layout_height="0dp"
+        android:layout_marginTop="@dimen/volume_dialog_background_vertical_margin"
+        android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin"
+        android:background="@drawable/volume_dialog_background"
+        app:layout_constraintBottom_toBottomOf="@id/volume_dialog_settings"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintTop_toTopOf="@id/volume_ringer_and_drawer_container" />
+
+    <include
+        android:id="@id/volume_ringer_and_drawer_container"
+        layout="@layout/volume_ringer_drawer"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|end"
+        android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
+        app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="1" />
+
+    <include
+        android:id="@+id/volume_dialog_main_slider_container"
+        layout="@layout/volume_dialog_slider" />
+
+    <ImageButton
+        android:id="@+id/volume_dialog_settings"
+        android:layout_width="@dimen/volume_dialog_button_size"
+        android:layout_height="@dimen/volume_dialog_button_size"
+        android:layout_marginTop="@dimen/volume_dialog_components_spacing"
+        android:background="@drawable/ripple_drawable_20dp"
+        android:contentDescription="@string/accessibility_volume_settings"
+        android:soundEffectsEnabled="false"
+        android:src="@drawable/horizontal_ellipsis"
+        android:tint="?androidprv:attr/materialColorPrimary"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintVertical_bias="0" />
+
+    <LinearLayout
+        android:id="@+id/volume_dialog_floating_sliders_container"
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:layout_marginTop="@dimen/volume_dialog_floating_sliders_vertical_padding_negative"
+        android:layout_marginBottom="@dimen/volume_dialog_floating_sliders_vertical_padding_negative"
         android:divider="@drawable/volume_dialog_floating_sliders_spacer"
+        android:gravity="bottom"
         android:orientation="horizontal"
-        android:showDividers="middle|end|beginning">
+        android:showDividers="middle|beginning|end"
+        app:layout_constraintBottom_toBottomOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toStartOf="@id/volume_dialog_background"
+        app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" />
 
-        <LinearLayout
-            android:id="@+id/volume_dialog_floating_sliders_container"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:divider="@drawable/volume_dialog_floating_sliders_spacer"
-            android:gravity="bottom"
-            android:orientation="horizontal"
-            android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding"
-            android:showDividers="middle" />
-
-        <LinearLayout
-            android:id="@+id/volume_dialog"
-            android:layout_width="@dimen/volume_dialog_width"
-            android:layout_height="wrap_content"
-            android:background="@drawable/volume_dialog_background"
-            android:clipChildren="false"
-            android:clipToOutline="false"
-            android:clipToPadding="false"
-            android:divider="@drawable/volume_dialog_spacer"
-            android:gravity="center_horizontal"
-            android:orientation="vertical"
-            android:paddingVertical="@dimen/volume_dialog_vertical_padding"
-            android:showDividers="middle">
-
-            <include layout="@layout/volume_ringer_drawer" />
-
-            <include layout="@layout/volume_dialog_slider" />
-
-            <ImageButton
-                android:id="@+id/volume_dialog_settings"
-                android:layout_width="@dimen/volume_dialog_button_size"
-                android:layout_height="@dimen/volume_dialog_button_size"
-                android:background="@drawable/ripple_drawable_20dp"
-                android:contentDescription="@string/accessibility_volume_settings"
-                android:soundEffectsEnabled="false"
-                android:src="@drawable/horizontal_ellipsis"
-                android:tint="?androidprv:attr/materialColorPrimary" />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
\ No newline at end of file
+</androidx.constraintlayout.motion.widget.MotionLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
index 7c266e6..b71c470 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -19,13 +19,10 @@
     android:id="@+id/volume_ringer_and_drawer_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:gravity="center"
-    android:paddingLeft="@dimen/volume_dialog_ringer_horizontal_padding"
-    android:paddingRight="@dimen/volume_dialog_ringer_horizontal_padding"
-    android:layoutDirection="ltr"
-    android:clipToPadding="false"
     android:clipChildren="false"
-    android:background="@drawable/volume_background_top">
+    android:clipToPadding="false"
+    android:gravity="center"
+    android:layoutDirection="ltr">
 
     <!-- Drawer view, invisible by default. -->
     <FrameLayout
@@ -37,10 +34,10 @@
         <!-- View that is animated to a tapped ringer selection, so it appears selected. -->
         <FrameLayout
             android:id="@+id/volume_drawer_selection_background"
-            android:alpha="0.0"
             android:layout_width="@dimen/volume_dialog_ringer_drawer_button_size"
             android:layout_height="@dimen/volume_dialog_ringer_drawer_button_size"
             android:layout_gravity="bottom|right"
+            android:alpha="0.0"
             android:background="@drawable/volume_drawer_selection_bg" />
 
         <LinearLayout
@@ -65,7 +62,6 @@
         android:background="@drawable/volume_drawer_selection_bg"
         android:contentDescription="@string/volume_ringer_change"
         android:gravity="center"
-        android:padding="@dimen/volume_dialog_ringer_horizontal_padding"
         android:src="@drawable/ic_volume_media"
         android:tint="?androidprv:attr/materialColorOnPrimary" />
 
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 4a53df9..75bee9f 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -46,8 +46,6 @@
 
     <dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen>
 
-    <dimen name="status_view_margin_horizontal">8dp</dimen>
-
     <!-- Lockscreen shade transition values -->
     <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
     <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 707bc9e..f73e91a 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -16,8 +16,6 @@
   -->
 <resources>
     <dimen name="notification_panel_margin_horizontal">48dp</dimen>
-    <dimen name="status_view_margin_horizontal">62dp</dimen>
-
     <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two
          pages is margin * 2, and that makes tiles page not appear immediately after user swipes to
          the side -->
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 8583f05..41bb37e 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -22,8 +22,6 @@
 
     <dimen name="keyguard_split_shade_top_margin">72dp</dimen>
 
-    <dimen name="status_view_margin_horizontal">24dp</dimen>
-
     <dimen name="qs_media_session_height_expanded">184dp</dimen>
     <dimen name="qs_content_horizontal_padding">40dp</dimen>
     <dimen name="qs_horizontal_margin">40dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index 9248d58..eb570b8 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -20,8 +20,6 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-    <dimen name="status_view_margin_horizontal">124dp</dimen>
-
     <dimen name="large_screen_shade_header_left_padding">24dp</dimen>
     <dimen name="qqs_layout_padding_bottom">40dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 67eb5b0..4954f91 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1805,10 +1805,9 @@
 
     <!-- Hearing devices dialog related dimensions -->
     <dimen name="hearing_devices_layout_margin">12dp</dimen>
-    <dimen name="hearing_devices_preset_spinner_height">72dp</dimen>
-    <dimen name="hearing_devices_preset_spinner_text_padding_start">20dp</dimen>
-    <dimen name="hearing_devices_preset_spinner_text_padding_vertical">15dp</dimen>
-    <dimen name="hearing_devices_preset_spinner_arrow_size">24dp</dimen>
+    <dimen name="hearing_devices_small_title_padding_horizontal">16dp</dimen>
+    <dimen name="hearing_devices_preset_spinner_padding">22dp</dimen>
+    <dimen name="hearing_devices_preset_spinner_icon_size">24dp</dimen>
     <dimen name="hearing_devices_preset_spinner_background_radius">28dp</dimen>
     <dimen name="hearing_devices_tool_icon_size">28dp</dimen>
 
@@ -1956,8 +1955,6 @@
     <dimen name="dream_overlay_entry_y_offset">40dp</dimen>
     <dimen name="dream_overlay_exit_y_offset">40dp</dimen>
 
-    <dimen name="status_view_margin_horizontal">0dp</dimen>
-
     <!-- Media output broadcast dialog QR code picture size -->
     <dimen name="media_output_qrcode_size">216dp</dimen>
     <dimen name="media_output_broadcast_info">21dp</dimen>
@@ -2061,26 +2058,29 @@
     <dimen name="contextual_edu_dialog_elevation">2dp</dimen>
 
     <!-- Volume start -->
-    <dimen name="volume_dialog_background_corner_radius">30dp</dimen>
     <dimen name="volume_dialog_width">60dp</dimen>
-    <dimen name="volume_dialog_vertical_padding">10dp</dimen>
+
+    <dimen name="volume_dialog_background_corner_radius">30dp</dimen>
+    <dimen name="volume_dialog_background_vertical_margin">-10dp</dimen>
+
     <dimen name="volume_dialog_components_spacing">8dp</dimen>
     <dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen>
     <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen>
+    <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen>
     <dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen>
-    <dimen name="volume_dialog_spacing">4dp</dimen>
     <dimen name="volume_dialog_button_size">48dp</dimen>
-    <dimen name="volume_dialog_floating_sliders_bottom_padding">48dp</dimen>
     <dimen name="volume_dialog_slider_width">52dp</dimen>
     <dimen name="volume_dialog_slider_height">254dp</dimen>
 
-    <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
-    <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
+    <fraction name="volume_dialog_half_opened_bias">0.2</fraction>
 
-    <dimen name="volume_dialog_ringer_horizontal_padding">10dp</dimen>
+    <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
+
     <dimen name="volume_dialog_ringer_drawer_button_size">40dp</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
-    <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
     <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
+
+    <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
+    <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
     <!-- Volume end -->
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53ab686..b45aadd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1002,6 +1002,10 @@
     <string name="hearing_devices_presets_error">Couldn\'t update preset</string>
     <!-- QuickSettings: Title for hearing aids presets. Preset is a set of hearing aid settings. User can apply different settings in different environments (e.g. Outdoor, Restaurant, Home) [CHAR LIMIT=40]-->
     <string name="hearing_devices_preset_label">Preset</string>
+    <!-- QuickSettings: Content description for the icon that indicates the item is selected [CHAR LIMIT=NONE]-->
+    <string name="hearing_devices_spinner_item_selected">Selected</string>
+    <!-- QuickSettings: Title for related tools of hearing. [CHAR LIMIT=40]-->
+    <string name="hearing_devices_tools_label">Tools</string>
     <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]-->
     <string name="quick_settings_hearing_devices_live_caption_title">Live Caption</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c69b98c..e14008a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1481,28 +1481,14 @@
         <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
     </style>
 
-    <style name="BluetoothTileDialog.Device.Active">
-        <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
-    </style>
-
-    <style name="BluetoothTileDialog.DeviceName">
-        <item name="android:textSize">14sp</item>
-        <item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item>
+    <style name="TextAppearance.BluetoothTileDialog">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textDirection">locale</item>
+        <item name="android:textAlignment">gravity</item>
         <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
     </style>
 
-    <style name="BluetoothTileDialog.DeviceSummary">
-        <item name="android:ellipsize">end</item>
-        <item name="android:maxLines">2</item>
-        <item name="android:textAppearance">@style/TextAppearance.Dialog.Body.Message</item>
-        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
-    </style>
-
-    <style name="BluetoothTileDialog.DeviceName.Active">
-        <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
-    </style>
-
-    <style name="BluetoothTileDialog.DeviceSummary.Active">
+    <style name="TextAppearance.BluetoothTileDialog.Active">
         <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item>
     </style>
 
diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
new file mode 100644
index 0000000..9018e5b
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/volume_dialog_constraint_set">
+
+    <Constraint
+        android:id="@id/volume_dialog_main_slider_container"
+        android:layout_width="@dimen/volume_dialog_slider_width"
+        android:layout_height="@dimen/volume_dialog_slider_height"
+        android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.5" />
+</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
new file mode 100644
index 0000000..297c388
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/volume_dialog_half_folded_constraint_set">
+
+    <Constraint
+        android:id="@id/volume_dialog_main_slider_container"
+        android:layout_width="@dimen/volume_dialog_slider_width"
+        android:layout_height="@dimen/volume_dialog_slider_height"
+        android:layout_marginEnd="@dimen/volume_dialog_components_spacing"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="@fraction/volume_dialog_half_opened_bias" />
+</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/volume_dialog_scene.xml b/packages/SystemUI/res/xml/volume_dialog_scene.xml
new file mode 100644
index 0000000..b813474
--- /dev/null
+++ b/packages/SystemUI/res/xml/volume_dialog_scene.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto">
+
+    <Transition
+        motion:autoTransition="none"
+        motion:constraintSetEnd="@id/volume_dialog_half_folded_constraint_set"
+        motion:constraintSetStart="@id/volume_dialog_constraint_set"
+        motion:duration="150" />
+
+    <Include motion:constraintSet="@xml/volume_dialog_constraint_set" />
+    <Include motion:constraintSet="@xml/volume_dialog_half_folded_constraint_set" />
+</MotionScene>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 95830b5..add459b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -44,7 +44,7 @@
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.views.NavigationBarView;
 import com.android.systemui.settings.DisplayTracker;
-import com.android.systemui.shade.data.repository.ShadePositionRepository;
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository;
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -66,7 +66,7 @@
     private final DisplayManager mDisplayService;
     private final DisplayTracker mDisplayTracker;
     private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
-    private final Provider<ShadePositionRepository> mShadePositionRepositoryProvider;
+    private final Provider<ShadeDisplaysRepository> mShadePositionRepositoryProvider;
     private final ConnectedDisplayKeyguardPresentation.Factory
             mConnectedDisplayKeyguardPresentationFactory;
     private final Context mContext;
@@ -112,7 +112,7 @@
             KeyguardStateController keyguardStateController,
             ConnectedDisplayKeyguardPresentation.Factory
                     connectedDisplayKeyguardPresentationFactory,
-            Provider<ShadePositionRepository> shadePositionRepositoryProvider,
+            Provider<ShadeDisplaysRepository> shadePositionRepositoryProvider,
             @Application CoroutineScope appScope) {
         mContext = context;
         mNavigationBarControllerLazy = navigationBarControllerLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 1978bb8..1f21af8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -35,10 +35,9 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.Visibility;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -114,10 +113,9 @@
     private SystemUIDialog mDialog;
     private RecyclerView mDeviceList;
     private List<DeviceItem> mHearingDeviceItemList;
+    private View mPresetLayout;
     private Spinner mPresetSpinner;
-    private ArrayAdapter<String> mPresetInfoAdapter;
-    private Button mPairButton;
-    private LinearLayout mRelatedToolsContainer;
+    private HearingDevicesSpinnerAdapter mPresetInfoAdapter;
     private final HearingDevicesPresetsController.PresetCallback mPresetCallback =
             new HearingDevicesPresetsController.PresetCallback() {
                 @Override
@@ -245,7 +243,7 @@
                     mPresetsController.getAllPresetInfo();
             final int activePresetIndex = mPresetsController.getActivePresetIndex();
             refreshPresetInfoAdapter(presetInfos, activePresetIndex);
-            mPresetSpinner.setVisibility(
+            mPresetLayout.setVisibility(
                     (activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
                             && !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
         });
@@ -291,14 +289,13 @@
         }
 
         mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId);
-        mPairButton = dialog.requireViewById(R.id.pair_new_device_button);
         mDeviceList = dialog.requireViewById(R.id.device_list);
+        mPresetLayout = dialog.requireViewById(R.id.preset_layout);
         mPresetSpinner = dialog.requireViewById(R.id.preset_spinner);
-        mRelatedToolsContainer = dialog.requireViewById(R.id.related_tools_container);
 
         setupDeviceListView(dialog);
         setupPresetSpinner(dialog);
-        setupPairNewDeviceButton(dialog, mShowPairNewDevice ? VISIBLE : GONE);
+        setupPairNewDeviceButton(dialog);
         if (com.android.systemui.Flags.hearingDevicesDialogRelatedTools()) {
             setupRelatedToolsView(dialog);
         }
@@ -353,11 +350,7 @@
                 mHearingDeviceItemList);
         mPresetsController.setHearingDeviceIfSupportHap(activeHearingDevice);
 
-        mPresetInfoAdapter = new ArrayAdapter<>(dialog.getContext(),
-                R.layout.hearing_devices_preset_spinner_selected,
-                R.id.hearing_devices_preset_option_text);
-        mPresetInfoAdapter.setDropDownViewResource(
-                R.layout.hearing_devices_preset_dropdown_item);
+        mPresetInfoAdapter = new HearingDevicesSpinnerAdapter(dialog.getContext());
         mPresetSpinner.setAdapter(mPresetInfoAdapter);
 
         // disable redundant Touch & Hold accessibility action for Switch Access
@@ -378,6 +371,7 @@
         mPresetSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                mPresetInfoAdapter.setSelected(position);
                 mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PRESET_SELECT,
                         mLaunchSourceId);
                 mPresetsController.selectPreset(
@@ -389,14 +383,17 @@
                 // Do nothing
             }
         });
-        mPresetSpinner.setVisibility(
+        mPresetLayout.setVisibility(
                 (activeHearingDevice != null && activeHearingDevice.isConnectedHapClientDevice()
                         && !mPresetInfoAdapter.isEmpty()) ? VISIBLE : GONE);
     }
 
-    private void setupPairNewDeviceButton(SystemUIDialog dialog, @Visibility int visibility) {
-        if (visibility == VISIBLE) {
-            mPairButton.setOnClickListener(v -> {
+    private void setupPairNewDeviceButton(SystemUIDialog dialog) {
+        final Button pairButton = dialog.requireViewById(R.id.pair_new_device_button);
+
+        pairButton.setVisibility(mShowPairNewDevice ? VISIBLE : GONE);
+        if (mShowPairNewDevice) {
+            pairButton.setOnClickListener(v -> {
                 mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR, mLaunchSourceId);
                 dismissDialogIfExists();
                 final Intent intent = new Intent(Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
@@ -404,12 +401,11 @@
                 mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
                         mDialogTransitionAnimator.createActivityTransitionController(dialog));
             });
-        } else {
-            mPairButton.setVisibility(GONE);
         }
     }
 
     private void setupRelatedToolsView(SystemUIDialog dialog) {
+
         final Context context = dialog.getContext();
         final List<ToolItem> toolItemList = new ArrayList<>();
         final String[] toolNameArray;
@@ -430,15 +426,20 @@
         } catch (Resources.NotFoundException e) {
             Log.i(TAG, "No hearing devices related tool config resource");
         }
+
+        final View toolsLayout = dialog.requireViewById(R.id.tools_layout);
+        toolsLayout.setVisibility(toolItemList.isEmpty() ? GONE : VISIBLE);
+
+        final LinearLayout toolsContainer = dialog.requireViewById(R.id.tools_container);
         for (int i = 0; i < toolItemList.size(); i++) {
-            View view = createHearingToolView(context, toolItemList.get(i));
-            mRelatedToolsContainer.addView(view);
+            View view = createHearingToolView(context, toolItemList.get(i), toolsContainer);
+            toolsContainer.addView(view);
             if (i != toolItemList.size() - 1) {
                 final int spaceSize = context.getResources().getDimensionPixelSize(
                         R.dimen.hearing_devices_layout_margin);
                 Space space = new Space(context);
                 space.setLayoutParams(new LinearLayout.LayoutParams(spaceSize, 0));
-                mRelatedToolsContainer.addView(space);
+                toolsContainer.addView(space);
             }
         }
     }
@@ -453,6 +454,7 @@
             for (int position = 0; position < size; position++) {
                 if (presetInfos.get(position).getIndex() == activePresetIndex) {
                     mPresetSpinner.setSelection(position, /* animate= */ false);
+                    mPresetInfoAdapter.setSelected(position);
                 }
             }
         }
@@ -493,9 +495,9 @@
     }
 
     @NonNull
-    private View createHearingToolView(Context context, ToolItem item) {
-        View view = LayoutInflater.from(context).inflate(R.layout.hearing_tool_item,
-                mRelatedToolsContainer, false);
+    private View createHearingToolView(Context context, ToolItem item, ViewGroup container) {
+        View view = LayoutInflater.from(context).inflate(R.layout.hearing_tool_item, container,
+                false);
         ImageView icon = view.requireViewById(R.id.tool_icon);
         TextView text = view.requireViewById(R.id.tool_name);
         view.setContentDescription(item.getToolName());
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
index 9367cb5..e47e4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java
@@ -138,19 +138,18 @@
 
             Pair<Drawable, String> iconPair = item.getIconWithDescription();
             if (iconPair != null) {
-                Drawable drawable = iconPair.getFirst().mutate();
-                drawable.setTint(tintColor);
+                Drawable drawable = iconPair.getFirst();
                 mIconView.setImageDrawable(drawable);
                 mIconView.setContentDescription(iconPair.getSecond());
             }
 
             mNameView.setTextAppearance(
-                    item.isActive() ? R.style.BluetoothTileDialog_DeviceName_Active
-                            : R.style.BluetoothTileDialog_DeviceName);
+                    item.isActive() ? R.style.TextAppearance_BluetoothTileDialog_Active
+                            : R.style.TextAppearance_BluetoothTileDialog);
             mNameView.setText(item.getDeviceName());
             mSummaryView.setTextAppearance(
-                    item.isActive() ? R.style.BluetoothTileDialog_DeviceSummary_Active
-                            : R.style.BluetoothTileDialog_DeviceSummary);
+                    item.isActive() ? R.style.TextAppearance_BluetoothTileDialog_Active
+                            : R.style.TextAppearance_BluetoothTileDialog);
             mSummaryView.setText(item.getConnectionSummary());
 
             mGearIcon.getDrawable().mutate().setTint(tintColor);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java
new file mode 100644
index 0000000..28d742c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java
@@ -0,0 +1,85 @@
+/*
+ * 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.accessibility.hearingaid;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.res.R;
+
+/**
+ * An ArrayAdapter which was used by Spinner in hearing devices dialog.
+ */
+public class HearingDevicesSpinnerAdapter extends ArrayAdapter<String> {
+
+    private final Context mContext;
+    private int mSelectedPosition;
+
+    public HearingDevicesSpinnerAdapter(@NonNull Context context) {
+        super(context, R.layout.hearing_devices_spinner_view,
+                R.id.hearing_devices_spinner_text);
+        setDropDownViewResource(R.layout.hearing_devices_spinner_dropdown_view);
+        mContext = context;
+    }
+
+    @Override
+    public View getDropDownView(int position, @Nullable View convertView,
+            @NonNull ViewGroup parent) {
+
+        View view = super.getDropDownView(position, convertView, parent);
+
+        final boolean isSelected = position == mSelectedPosition;
+        view.setBackgroundResource(isSelected
+                ? R.drawable.hearing_devices_spinner_selected_background
+                : R.drawable.bluetooth_tile_dialog_bg_off);
+
+        View checkIcon = view.findViewById(R.id.hearing_devices_spinner_check_icon);
+        if (checkIcon != null) {
+            checkIcon.setVisibility(isSelected ? VISIBLE : GONE);
+        }
+
+        TextView text = view.findViewById(R.id.hearing_devices_spinner_text);
+        if (text != null) {
+            int tintColor = Utils.getColorAttr(mContext,
+                    isSelected ? com.android.internal.R.attr.materialColorOnPrimaryContainer
+                            : com.android.internal.R.attr.materialColorOnSurface).getDefaultColor();
+            text.setTextColor(tintColor);
+        }
+        return view;
+    }
+
+    /**
+     * Sets the selected position into this adapter. The selected item will have different UI in
+     * the dropdown view.
+     *
+     * @param position the selected position
+     */
+    public void setSelected(int position) {
+        mSelectedPosition = position;
+        notifyDataSetChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
index fb00d6e..db4d613 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
@@ -52,6 +52,8 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import kotlin.Unit;
+
 import kotlinx.coroutines.Job;
 
 import java.util.Collection;
@@ -87,7 +89,7 @@
     private final ConfigurationInteractor mConfigurationInteractor;
 
     private final Lifecycle mLifecycle;
-    private Rect mExclusionRect = null;
+    private Rect mExclusionRect = new Rect();
 
     private ISystemGestureExclusionListener mGestureExclusionListener;
 
@@ -298,9 +300,18 @@
                         public void onSystemGestureExclusionChanged(int displayId,
                                 Region systemGestureExclusion,
                                 Region systemGestureExclusionUnrestricted) {
-                            mExclusionRect = systemGestureExclusion.getBounds();
+                            final Rect bounds = systemGestureExclusion.getBounds();
+                            if (!mExclusionRect.equals(bounds)) {
+                                mExclusionRect = bounds;
+                                mLogger.i(msg -> "Exclusion rect updated to " + msg.getStr1(),
+                                        msg -> {
+                                            msg.setStr1(bounds.toString());
+                                            return Unit.INSTANCE;
+                                        });
+                            }
                         }
                     };
+                    mLogger.i("Registering system gesture exclusion listener");
                     mWindowManagerService.registerSystemGestureExclusionListener(
                             mGestureExclusionListener, mDisplayId);
                 } catch (RemoteException e) {
@@ -320,11 +331,12 @@
      * Destroys any active {@link InputSession}.
      */
     private void stopMonitoring(boolean force) {
-        mExclusionRect = null;
+        mExclusionRect = new Rect();
         if (bouncerAreaExclusion()) {
             mBackgroundExecutor.execute(() -> {
                 try {
                     if (mGestureExclusionListener != null) {
+                        mLogger.i("Unregistering system gesture exclusion listener");
                         mWindowManagerService.unregisterSystemGestureExclusionListener(
                                 mGestureExclusionListener, mDisplayId);
                         mGestureExclusionListener = null;
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
index a9c5c69..d7a0fc9 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt
@@ -100,7 +100,7 @@
             initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
             cachedContentHeight: Int,
             dialogCallback: BluetoothTileDialogCallback,
-            dimissListener: Runnable
+            dimissListener: Runnable,
         ): BluetoothTileDialogDelegate
     }
 
@@ -135,7 +135,7 @@
                 object : AccessibilityDelegate() {
                     override fun onInitializeAccessibilityNodeInfo(
                         host: View,
-                        info: AccessibilityNodeInfo
+                        info: AccessibilityNodeInfo,
                     ) {
                         super.onInitializeAccessibilityNodeInfo(host, info)
                         info.addAction(
@@ -144,7 +144,7 @@
                                 context.getString(
                                     R.string
                                         .quick_settings_bluetooth_audio_sharing_button_accessibility
-                                )
+                                ),
                             )
                         )
                     }
@@ -180,7 +180,7 @@
         dialog: SystemUIDialog,
         deviceItem: List<DeviceItem>,
         showSeeAll: Boolean,
-        showPairNewDevice: Boolean
+        showPairNewDevice: Boolean,
     ) {
         withContext(mainDispatcher) {
             val start = systemClock.elapsedRealtime()
@@ -207,7 +207,7 @@
     internal fun onBluetoothStateUpdated(
         dialog: SystemUIDialog,
         isEnabled: Boolean,
-        uiProperties: BluetoothTileDialogViewModel.UiProperties
+        uiProperties: BluetoothTileDialogViewModel.UiProperties,
     ) {
         getToggleView(dialog).apply {
             isChecked = isEnabled
@@ -221,7 +221,7 @@
     internal fun onBluetoothAutoOnUpdated(
         dialog: SystemUIDialog,
         isEnabled: Boolean,
-        @StringRes infoResId: Int
+        @StringRes infoResId: Int,
     ) {
         getAutoOnToggle(dialog).isChecked = isEnabled
         getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId)
@@ -231,7 +231,7 @@
         dialog: SystemUIDialog,
         visibility: Int,
         label: String?,
-        isActive: Boolean
+        isActive: Boolean,
     ) {
         getAudioSharingButtonView(dialog).apply {
             this.visibility = visibility
@@ -339,14 +339,14 @@
             object : DiffUtil.ItemCallback<DeviceItem>() {
                 override fun areItemsTheSame(
                     deviceItem1: DeviceItem,
-                    deviceItem2: DeviceItem
+                    deviceItem2: DeviceItem,
                 ): Boolean {
                     return deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice
                 }
 
                 override fun areContentsTheSame(
                     deviceItem1: DeviceItem,
-                    deviceItem2: DeviceItem
+                    deviceItem2: DeviceItem,
                 ): Boolean {
                     return deviceItem1.type == deviceItem2.type &&
                         deviceItem1.cachedBluetoothDevice == deviceItem2.cachedBluetoothDevice &&
@@ -394,7 +394,7 @@
 
             internal fun bind(
                 item: DeviceItem,
-                deviceItemOnClickCallback: BluetoothTileDialogCallback
+                deviceItemOnClickCallback: BluetoothTileDialogCallback,
             ) {
                 container.apply {
                     isEnabled = item.isEnabled
@@ -409,14 +409,14 @@
                         com.android.settingslib.Utils.getColorAttr(
                                 context,
                                 if (item.isActive) InternalR.attr.materialColorOnPrimaryContainer
-                                else InternalR.attr.materialColorOnSurface
+                                else InternalR.attr.materialColorOnSurface,
                             )
                             .defaultColor
 
                     // update icons
                     iconView.apply {
                         item.iconWithDescription?.let {
-                            setImageDrawable(it.first.apply { mutate()?.setTint(tintColor) })
+                            setImageDrawable(it.first)
                             contentDescription = it.second
                         }
                     }
@@ -427,25 +427,25 @@
 
                     // update text styles
                     nameView.setTextAppearance(
-                        if (item.isActive) R.style.BluetoothTileDialog_DeviceName_Active
-                        else R.style.BluetoothTileDialog_DeviceName
+                        if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
+                        else R.style.TextAppearance_BluetoothTileDialog
                     )
                     summaryView.setTextAppearance(
-                        if (item.isActive) R.style.BluetoothTileDialog_DeviceSummary_Active
-                        else R.style.BluetoothTileDialog_DeviceSummary
+                        if (item.isActive) R.style.TextAppearance_BluetoothTileDialog_Active
+                        else R.style.TextAppearance_BluetoothTileDialog
                     )
 
                     accessibilityDelegate =
                         object : AccessibilityDelegate() {
                             override fun onInitializeAccessibilityNodeInfo(
                                 host: View,
-                                info: AccessibilityNodeInfo
+                                info: AccessibilityNodeInfo,
                             ) {
                                 super.onInitializeAccessibilityNodeInfo(host, info)
                                 info.addAction(
                                     AccessibilityAction(
                                         AccessibilityAction.ACTION_CLICK.id,
-                                        item.actionAccessibilityLabel
+                                        item.actionAccessibilityLabel,
                                     )
                                 )
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index 2921373..92f0580 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -57,7 +57,6 @@
     companion object {
         @JvmStatic
         fun createDeviceItem(
-            context: Context,
             cachedDevice: CachedBluetoothDevice,
             type: DeviceItemType,
             connectionSummary: String,
@@ -71,9 +70,7 @@
                 deviceName = cachedDevice.name,
                 connectionSummary = connectionSummary,
                 iconWithDescription =
-                    BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let {
-                        Pair(it.first, it.second)
-                    },
+                    cachedDevice.drawableWithDescription.let { Pair(it.first, it.second) },
                 background = background,
                 isEnabled = !cachedDevice.isBusy,
                 actionAccessibilityLabel = actionAccessibilityLabel,
@@ -96,7 +93,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
             cachedDevice.connectionSummary ?: "",
@@ -122,7 +118,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
             cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -153,7 +148,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,
             context.getString(
@@ -191,7 +185,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
             cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -232,7 +225,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
             cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
@@ -262,7 +254,6 @@
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
         return createDeviceItem(
-            context,
             cachedDevice,
             DeviceItemType.SAVED_BLUETOOTH_DEVICE,
             cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() }
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index 917a4ff..ccd953d 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -24,6 +24,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
@@ -31,7 +32,6 @@
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
@@ -61,6 +61,7 @@
 import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
 import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
 import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
 import com.android.systemui.res.R
 import com.android.systemui.utils.PolicyRestriction
 
@@ -102,11 +103,12 @@
             null
         }
 
-    val overriddenByAppState by if (Flags.showToastWhenAppControlBrightness()) {
-        viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle()
-    } else {
-        mutableStateOf(false)
-    }
+    val overriddenByAppState =
+        if (Flags.showToastWhenAppControlBrightness()) {
+            viewModel.brightnessOverriddenByWindow.collectAsStateWithLifecycle().value
+        } else {
+            false
+        }
 
     PlatformSlider(
         value = animatedValue,
@@ -160,7 +162,7 @@
                 if (interaction is DragInteraction.Start && overriddenByAppState) {
                     viewModel.showToast(
                         context,
-                        R.string.quick_settings_brightness_unable_adjust_msg
+                        R.string.quick_settings_brightness_unable_adjust_msg,
                     )
                 }
             }
@@ -213,7 +215,11 @@
                 coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) }
             },
             modifier =
-                Modifier.then(if (viewModel.showMirror) Modifier.drawInOverlay() else Modifier)
+                Modifier.borderOnFocus(
+                        color = MaterialTheme.colorScheme.secondary,
+                        cornerSize = CornerSize(32.dp),
+                    )
+                    .then(if (viewModel.showMirror) Modifier.drawInOverlay() else Modifier)
                     .sliderBackground(containerColor)
                     .fillMaxWidth(),
             formatter = viewModel::formatValue,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
index 7cfad60..6423f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalMetricsLogger.kt
@@ -30,6 +30,7 @@
     @Named(LOGGABLE_PREFIXES) private val loggablePrefixes: List<String>,
     private val statsLogProxy: StatsLogProxy,
 ) {
+
     /** Logs an add widget event for metrics. No-op if widget is not loggable. */
     fun logAddWidget(componentName: String, rank: Int?) {
         if (!componentName.isLoggable()) {
@@ -69,11 +70,21 @@
         )
     }
 
+    fun logResizeWidget(componentName: String, rank: Int, spanY: Int = 0) {
+        if (!componentName.isLoggable()) {
+            return
+        }
+
+        statsLogProxy.writeCommunalHubWidgetEventReported(
+            SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED__ACTION__RESIZE,
+            componentName,
+            rank = rank,
+            spanY = spanY,
+        )
+    }
+
     /** Logs loggable widgets and the total widget count as a [StatsEvent]. */
-    fun logWidgetsSnapshot(
-        statsEvents: MutableList<StatsEvent>,
-        componentNames: List<String>,
-    ) {
+    fun logWidgetsSnapshot(statsEvents: MutableList<StatsEvent>, componentNames: List<String>) {
         val loggableComponentNames = componentNames.filter { it.isLoggable() }.toTypedArray()
         statsEvents.add(
             statsLogProxy.buildCommunalHubSnapshotStatsEvent(
@@ -95,6 +106,7 @@
             action: Int,
             componentName: String,
             rank: Int,
+            spanY: Int = 0,
         )
 
         /** Builds a [SysUiStatsLog.COMMUNAL_HUB_SNAPSHOT] stats event. */
@@ -112,12 +124,14 @@
         action: Int,
         componentName: String,
         rank: Int,
+        spanY: Int,
     ) {
         SysUiStatsLog.write(
             SysUiStatsLog.COMMUNAL_HUB_WIDGET_EVENT_REPORTED,
             action,
             componentName,
             rank,
+            spanY,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index e25ea4c..5ecf2e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.communal.shared.model.EditModeState
 import com.android.systemui.communal.widgets.WidgetConfigurator
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
 import com.android.systemui.util.kotlin.BooleanFlowOperators.not
@@ -43,6 +44,7 @@
     val communalSceneInteractor: CommunalSceneInteractor,
     private val communalInteractor: CommunalInteractor,
     val mediaHost: MediaHost,
+    val mediaCarouselController: MediaCarouselController,
 ) {
     val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene
 
@@ -178,7 +180,13 @@
      *   alongside the resize, in case resizing also requires re-ordering. This ensures the
      *   re-ordering is done in the same database transaction as the resize.
      */
-    open fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {}
+    open fun onResizeWidget(
+        appWidgetId: Int,
+        spanY: Int,
+        widgetIdToRankMap: Map<Int, Int>,
+        componentName: ComponentName,
+        rank: Int,
+    ) {}
 
     /** Called as the UI requests opening the widget editor with an optional preselected widget. */
     open fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 6508e4b5..736ed5c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -46,6 +46,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule
 import com.android.systemui.res.R
@@ -82,7 +83,14 @@
     private val accessibilityManager: AccessibilityManager,
     private val packageManager: PackageManager,
     @Named(LAUNCHER_PACKAGE) private val launcherPackage: String,
-) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) {
+    mediaCarouselController: MediaCarouselController,
+) :
+    BaseCommunalViewModel(
+        communalSceneInteractor,
+        communalInteractor,
+        mediaHost,
+        mediaCarouselController,
+    ) {
 
     private val logger = Logger(logBuffer, "CommunalEditModeViewModel")
 
@@ -141,8 +149,19 @@
     override fun onReorderWidgets(widgetIdToRankMap: Map<Int, Int>) =
         communalInteractor.updateWidgetOrder(widgetIdToRankMap)
 
-    override fun onResizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+    override fun onResizeWidget(
+        appWidgetId: Int,
+        spanY: Int,
+        widgetIdToRankMap: Map<Int, Int>,
+        componentName: ComponentName,
+        rank: Int,
+    ) {
         communalInteractor.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+        metricsLogger.logResizeWidget(
+            componentName = componentName.flattenToString(),
+            rank = rank,
+            spanY = spanY,
+        )
     }
 
     override fun onReorderWidgetStart() {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
index 6239373..3496230 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
 import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
@@ -41,6 +42,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onStart
@@ -60,7 +62,7 @@
     glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel,
     communalInteractor: CommunalInteractor,
     private val communalSceneInteractor: CommunalSceneInteractor,
-    keyguardTransitionInteractor: KeyguardTransitionInteractor
+    keyguardTransitionInteractor: KeyguardTransitionInteractor,
 ) {
     /**
      * Snaps to [CommunalScenes.Communal], showing the glanceable hub immediately without any
@@ -89,7 +91,7 @@
         keyguardTransitionInteractor
             .transition(
                 edge = Edge.create(from = Scenes.Communal),
-                edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB)
+                edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB),
             )
             .filter {
                 it.to == KeyguardState.OCCLUDED &&
@@ -114,21 +116,24 @@
                     // from
                     // the hub, then pressing power twice to go back to the lock screen.
                     communalSceneInteractor.isCommunalVisible,
-                    merge(
-                            lockscreenToGlanceableHubTransitionViewModel.showUmo,
-                            glanceableHubToLockscreenTransitionViewModel.showUmo,
-                            dreamToGlanceableHubTransitionViewModel.showUmo,
-                            glanceableHubToDreamTransitionViewModel.showUmo,
-                            showUmoFromOccludedToGlanceableHub,
-                            showUmoFromGlanceableHubToOccluded,
-                        )
-                        .onStart { emit(false) }
-                )
+                    // TODO(b/378942852): polish UMO transitions when scene container is enabled
+                    if (SceneContainerFlag.isEnabled) flowOf(true)
+                    else
+                        merge(
+                                lockscreenToGlanceableHubTransitionViewModel.showUmo,
+                                glanceableHubToLockscreenTransitionViewModel.showUmo,
+                                dreamToGlanceableHubTransitionViewModel.showUmo,
+                                glanceableHubToDreamTransitionViewModel.showUmo,
+                                showUmoFromOccludedToGlanceableHub,
+                                showUmoFromGlanceableHubToOccluded,
+                            )
+                            .onStart { emit(false) },
+                ),
             )
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = false
+                initialValue = false,
             )
 
     /** Whether to show communal when exiting the occluded state. */
@@ -145,8 +150,7 @@
     val recentsBackgroundColor: Flow<Color?> =
         combine(showCommunalFromOccluded, communalColors.backgroundColor) {
             showCommunalFromOccluded,
-            backgroundColor,
-            ->
+            backgroundColor ->
             if (showCommunalFromOccluded) {
                 backgroundColor
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 7990450..9cd6465 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -21,6 +21,7 @@
 import android.os.Bundle
 import android.view.View
 import android.view.accessibility.AccessibilityNodeInfo
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
@@ -38,6 +39,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
+import com.android.systemui.media.controls.ui.controller.MediaCarouselController
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.controls.ui.view.MediaHostState
@@ -72,7 +74,6 @@
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** The default view model used for showing the communal hub. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -95,7 +96,14 @@
     @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
     @CommunalLog logBuffer: LogBuffer,
     private val metricsLogger: CommunalMetricsLogger,
-) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) {
+    mediaCarouselController: MediaCarouselController,
+) :
+    BaseCommunalViewModel(
+        communalSceneInteractor,
+        communalInteractor,
+        mediaHost,
+        mediaCarouselController,
+    ) {
 
     private val logger = Logger(logBuffer, "CommunalViewModel")
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4447dff..b7d3c92 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -100,7 +100,7 @@
 import com.android.systemui.qs.footer.dagger.FooterActionsModule;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recordissue.RecordIssueModule;
-import com.android.systemui.retail.dagger.RetailModeModule;
+import com.android.systemui.retail.RetailModeModule;
 import com.android.systemui.scene.shared.model.SceneContainerConfig;
 import com.android.systemui.scene.shared.model.SceneDataSource;
 import com.android.systemui.scene.shared.model.SceneDataSourceDelegator;
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
index b74ca03..35eed5e 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
 import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
 import javax.inject.Inject
@@ -363,6 +364,9 @@
         private val interactor: DeviceUnlockedInteractor,
     ) : CoreStartable {
         override fun start() {
+            if (!SceneContainerFlag.isEnabled)
+                return
+
             applicationScope.launch { interactor.activate() }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
index 80eb9ee..f310b30 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.shared.model.DisplayWindowProperties
 import com.android.systemui.res.R
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.google.common.collect.HashBasedTable
 import com.google.common.collect.Table
@@ -60,7 +61,10 @@
 ) : DisplayWindowPropertiesRepository, CoreStartable {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        check(StatusBarConnectedDisplays.isEnabled || ShadeWindowGoesAround.isEnabled) {
+            "This should be instantiated only when wither StatusBarConnectedDisplays or " +
+                "ShadeWindowGoesAround are enabled."
+        }
     }
 
     private val properties: Table<Int, Int, DisplayWindowProperties> = HashBasedTable.create()
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index ecddef6..711534f 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -17,13 +17,12 @@
 package com.android.systemui.display.data.repository
 
 import android.view.Display
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.qualifiers.Background
 import java.io.PrintWriter
 import java.util.concurrent.ConcurrentHashMap
-import kotlinx.coroutines.CoroutineName
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /** Provides per display instances of [T]. */
 interface PerDisplayStore<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 89fce4a..abc810a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -469,9 +469,8 @@
                     || posture >= mLightSensorOptional.length) {
                 return;
             }
-
-            final Sensor oldSensor = mLightSensorOptional[mDevicePosture].get();
-            final Sensor newSensor = mLightSensorOptional[posture].get();
+            Sensor oldSensor = mLightSensorOptional[mDevicePosture].orElse(null);
+            Sensor newSensor = mLightSensorOptional[posture].orElse(null);
             if (Objects.equals(oldSensor, newSensor)) {
                 mDevicePosture = posture;
                 // uses the same sensor for the new posture
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 1ffbbd2..b330ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -65,6 +65,9 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
 import com.android.systemui.navigationbar.gestural.domain.GestureInteractor;
 import com.android.systemui.navigationbar.gestural.domain.TaskMatcher;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.touch.TouchInsetManager;
 import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -162,6 +165,7 @@
 
     private TouchMonitor mTouchMonitor;
 
+    private final SceneInteractor mSceneInteractor;
     private final CommunalInteractor mCommunalInteractor;
 
     private boolean mCommunalAvailable;
@@ -378,6 +382,7 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             ScrimManager scrimManager,
             CommunalInteractor communalInteractor,
+            SceneInteractor sceneInteractor,
             SystemDialogsCloser systemDialogsCloser,
             UiEventLogger uiEventLogger,
             @Named(DREAM_TOUCH_INSET_MANAGER) TouchInsetManager touchInsetManager,
@@ -405,6 +410,7 @@
         mDreamOverlayCallbackController = dreamOverlayCallbackController;
         mWindowTitle = windowTitle;
         mCommunalInteractor = communalInteractor;
+        mSceneInteractor = sceneInteractor;
         mSystemDialogsCloser = systemDialogsCloser;
         mGestureInteractor = gestureInteractor;
         mDreamOverlayComponentFactory = dreamOverlayComponentFactory;
@@ -551,9 +557,15 @@
     @Override
     public void onWakeRequested() {
         mUiEventLogger.log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START);
-        mCommunalInteractor.changeScene(CommunalScenes.Communal,
-                "dream wake requested",
-                null);
+        if (SceneContainerFlag.isEnabled()) {
+            // Scene interactor can only be modified on main thread.
+            mExecutor.execute(() -> mSceneInteractor.changeScene(Scenes.Communal,
+                    "dream wake redirect to communal"));
+        } else {
+            mCommunalInteractor.changeScene(CommunalScenes.Communal,
+                    "dream wake requested",
+                    null);
+        }
     }
 
     private void updateGestureBlockingLocked() {
@@ -617,7 +629,13 @@
         mSystemDialogsCloser.closeSystemDialogs();
 
         // Hide glanceable hub (this is a nop if glanceable hub is not open).
-        mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null);
+        if (SceneContainerFlag.isEnabled()) {
+            // Scene interactor can only be modified on main thread.
+            mExecutor.execute(
+                    () -> mSceneInteractor.changeScene(Scenes.Dream, "closing hub to go to dream"));
+        } else {
+            mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
index 8b6cc8c..5a9e52a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt
@@ -16,17 +16,66 @@
 
 package com.android.systemui.dreams.ui.viewmodel
 
+import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.shade.ui.viewmodel.dualShadeActions
+import com.android.systemui.shade.ui.viewmodel.singleShadeActions
+import com.android.systemui.shade.ui.viewmodel.splitShadeActions
+import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 
 /** Handles user input for the dream scene. */
-class DreamUserActionsViewModel @AssistedInject constructor() : UserActionsViewModel() {
+class DreamUserActionsViewModel
+@AssistedInject
+constructor(
+    private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
+    private val shadeInteractor: ShadeInteractor,
+) : UserActionsViewModel() {
 
     override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
-        setActions(emptyMap())
+        shadeInteractor.isShadeTouchable
+            .flatMapLatestConflated { isShadeTouchable ->
+                if (!isShadeTouchable) {
+                    flowOf(emptyMap())
+                } else {
+                    combine(
+                        deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked },
+                        shadeInteractor.shadeMode,
+                    ) { isDeviceUnlocked, shadeMode ->
+                        buildList {
+                                add(Swipe.Start to Scenes.Communal)
+
+                                val bouncerOrGone =
+                                    if (isDeviceUnlocked) Scenes.Gone else Scenes.Bouncer
+                                add(Swipe.Up to bouncerOrGone)
+
+                                // "Home" is either Dream, Lockscreen, or Gone.
+                                add(Swipe.End to SceneFamilies.Home)
+
+                                addAll(
+                                    when (shadeMode) {
+                                        ShadeMode.Single -> singleShadeActions()
+                                        ShadeMode.Split -> splitShadeActions()
+                                        ShadeMode.Dual -> dualShadeActions()
+                                    }
+                                )
+                            }
+                            .associate { it }
+                    }
+                }
+            }
+            .collect { setActions(it) }
     }
 
     @AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
index ca43871..25f9920 100644
--- a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
@@ -27,7 +27,6 @@
 import android.content.res.Resources.NotFoundException
 import android.graphics.Bitmap
 import android.graphics.ImageDecoder
-import android.graphics.ImageDecoder.DecodeException
 import android.graphics.drawable.AdaptiveIconDrawable
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
@@ -39,7 +38,6 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
-import java.io.IOException
 import javax.inject.Inject
 import kotlin.math.min
 import kotlinx.coroutines.CoroutineDispatcher
@@ -54,7 +52,7 @@
 @Inject
 constructor(
     @Application private val defaultContext: Context,
-    @Background private val backgroundDispatcher: CoroutineDispatcher
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) {
 
     /** Source of the image data. */
@@ -103,7 +101,7 @@
         source: Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Bitmap? =
         withContext(backgroundDispatcher) { loadBitmapSync(source, maxWidth, maxHeight, allocator) }
 
@@ -127,14 +125,14 @@
         source: Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Bitmap? {
         return try {
             loadBitmapSync(
                 toImageDecoderSource(source, defaultContext),
                 maxWidth,
                 maxHeight,
-                allocator
+                allocator,
             )
         } catch (e: NotFoundException) {
             Log.w(TAG, "Couldn't load resource $source", e)
@@ -162,7 +160,7 @@
         source: ImageDecoder.Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Bitmap? =
         traceSection("ImageLoader#loadBitmap") {
             return try {
@@ -170,12 +168,11 @@
                     configureDecoderForMaximumSize(decoder, info.size, maxWidth, maxHeight)
                     decoder.allocator = allocator
                 }
-            } catch (e: IOException) {
+            } catch (e: Exception) {
+                // If we're loading an Uri, we can receive any exception from the other side.
+                // So we have to catch them all.
                 Log.w(TAG, "Failed to load source $source", e)
                 return null
-            } catch (e: DecodeException) {
-                Log.w(TAG, "Failed to decode source $source", e)
-                return null
             }
         }
 
@@ -199,7 +196,7 @@
         source: Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Drawable? =
         withContext(backgroundDispatcher) {
             loadDrawableSync(source, maxWidth, maxHeight, allocator)
@@ -227,7 +224,7 @@
         context: Context = defaultContext,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Drawable? =
         withContext(backgroundDispatcher) {
             loadDrawableSync(icon, context, maxWidth, maxHeight, allocator)
@@ -254,7 +251,7 @@
         source: Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Drawable? =
         traceSection("ImageLoader#loadDrawable") {
             return try {
@@ -262,7 +259,7 @@
                     toImageDecoderSource(source, defaultContext),
                     maxWidth,
                     maxHeight,
-                    allocator
+                    allocator,
                 )
                     ?:
                     // If we have a resource, retry fallback using the "normal" Resource loading
@@ -301,7 +298,7 @@
         source: ImageDecoder.Source,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Drawable? =
         traceSection("ImageLoader#loadDrawable") {
             return try {
@@ -309,12 +306,11 @@
                     configureDecoderForMaximumSize(decoder, info.size, maxWidth, maxHeight)
                     decoder.allocator = allocator
                 }
-            } catch (e: IOException) {
+            } catch (e: Exception) {
+                // If we're loading from an Uri, any exception can happen on the
+                // other side. We have to catch them all.
                 Log.w(TAG, "Failed to load source $source", e)
                 return null
-            } catch (e: DecodeException) {
-                Log.w(TAG, "Failed to decode source $source", e)
-                return null
             }
         }
 
@@ -325,7 +321,7 @@
         context: Context = defaultContext,
         @Px maxWidth: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
         @Px maxHeight: Int = DEFAULT_MAX_SAFE_BITMAP_SIZE_PX,
-        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT
+        allocator: Int = ImageDecoder.ALLOCATOR_DEFAULT,
     ): Drawable? =
         traceSection("ImageLoader#loadDrawable") {
             return when (icon.type) {
@@ -341,7 +337,7 @@
                             ImageDecoder.createSource(it, icon.resId),
                             maxWidth,
                             maxHeight,
-                            allocator
+                            allocator,
                         )
                     }
                         // Fallback to non-ImageDecoder load if the attempt failed (e.g. the
@@ -360,7 +356,7 @@
                         ImageDecoder.createSource(icon.dataBytes, icon.dataOffset, icon.dataLength),
                         maxWidth,
                         maxHeight,
-                        allocator
+                        allocator,
                     )
                 }
                 else -> {
@@ -421,12 +417,10 @@
     fun loadSizeSync(source: ImageDecoder.Source): Size? {
         return try {
             ImageDecoder.decodeHeader(source).size
-        } catch (e: IOException) {
+        } catch (e: Exception) {
+            // Any exception can happen when loading Uris, so we have to catch them all.
             Log.w(TAG, "Failed to load source $source", e)
             return null
-        } catch (e: DecodeException) {
-            Log.w(TAG, "Failed to decode source $source", e)
-            return null
         }
     }
 
@@ -472,7 +466,7 @@
             decoder: ImageDecoder,
             imgSize: Size,
             @Px maxWidth: Int,
-            @Px maxHeight: Int
+            @Px maxHeight: Int,
         ) {
             if (maxWidth == DO_NOT_RESIZE && maxHeight == DO_NOT_RESIZE) {
                 return
@@ -547,7 +541,7 @@
                     pm.getApplicationInfo(
                         resPackage,
                         PackageManager.MATCH_UNINSTALLED_PACKAGES or
-                            PackageManager.GET_SHARED_LIBRARY_FILES
+                            PackageManager.GET_SHARED_LIBRARY_FILES,
                     )
                 if (ai != null) {
                     return pm.getResourcesForApplication(ai)
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
index ed7d182..316964a 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt
@@ -83,9 +83,6 @@
                     interactionState == TileInteractionState.LONG_CLICKED &&
                         animationState == TileAnimationState.ACTIVITY_LAUNCH ->
                         TileHapticsState.LONG_PRESS
-                    interactionState == TileInteractionState.LONG_CLICKED &&
-                        !tileViewModel.currentState.handlesLongClick ->
-                        TileHapticsState.FAILED_LONGPRESS
                     else -> TileHapticsState.NO_HAPTICS
                 }
             }
@@ -102,7 +99,6 @@
                         TileHapticsState.TOGGLE_ON -> MSDLToken.SWITCH_ON
                         TileHapticsState.TOGGLE_OFF -> MSDLToken.SWITCH_OFF
                         TileHapticsState.LONG_PRESS -> MSDLToken.LONG_PRESS
-                        TileHapticsState.FAILED_LONGPRESS -> MSDLToken.FAILURE
                         TileHapticsState.NO_HAPTICS -> null
                     }
                 tokenToPlay?.let {
@@ -154,7 +150,6 @@
         TOGGLE_ON,
         TOGGLE_OFF,
         LONG_PRESS,
-        FAILED_LONGPRESS,
         NO_HAPTICS,
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
index 7f8fbb5..ec1d358 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt
@@ -49,6 +49,7 @@
     @Background private val backgroundScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val shortcutCategoriesUtils: ShortcutCategoriesUtils,
+    private val context: Context,
 ) : ShortcutCategoriesRepository {
 
     private val userContext: Context
@@ -147,25 +148,23 @@
     private fun fetchGroupLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        return InputGestures.gestureToInternalKeyboardShortcutGroupLabelMap.getOrDefault(
-            keyGestureType,
-            null,
-        )
+        InputGestures.gestureToInternalKeyboardShortcutGroupLabelMap[keyGestureType]?.let {
+            return context.getString(it)
+        } ?: return null
     }
 
     private fun fetchShortcutInfoLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        return InputGestures.gestureToInternalKeyboardShortcutInfoLabelMap.getOrDefault(
-            keyGestureType,
-            null,
-        )
+        InputGestures.gestureToInternalKeyboardShortcutInfoLabelMap[keyGestureType]?.let {
+            return context.getString(it)
+        } ?: return null
     }
 
     private fun fetchShortcutCategoryTypeByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): ShortcutCategoryType? {
-        return InputGestures.gestureToShortcutCategoryTypeMap.getOrDefault(keyGestureType, null)
+        return InputGestures.gestureToShortcutCategoryTypeMap[keyGestureType]
     }
 
     private data class InternalGroupsSource(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
index 28134db..90be988 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestures.kt
@@ -44,6 +44,7 @@
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
+import com.android.systemui.res.R
 
 object InputGestures {
     val gestureToShortcutCategoryTypeMap =
@@ -80,77 +81,97 @@
             KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to AppCategories,
         )
 
-    // TODO move all string to to resources use the same resources as the original shortcuts
-    // - that way when the strings are translated there are no discrepancies
     val gestureToInternalKeyboardShortcutGroupLabelMap =
         mapOf(
             // System Category
-            KEY_GESTURE_TYPE_HOME to "System controls",
-            KEY_GESTURE_TYPE_RECENT_APPS to "System controls",
-            KEY_GESTURE_TYPE_BACK to "System controls",
-            KEY_GESTURE_TYPE_TAKE_SCREENSHOT to "System controls",
-            KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to "System controls",
-            KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to "System controls",
-            KEY_GESTURE_TYPE_LOCK_SCREEN to "System controls",
-            KEY_GESTURE_TYPE_ALL_APPS to "System controls",
-            KEY_GESTURE_TYPE_OPEN_NOTES to "System apps",
-            KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to "System apps",
-            KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to "System apps",
-            KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to "System apps",
+            KEY_GESTURE_TYPE_HOME to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_RECENT_APPS to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_BACK to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_TAKE_SCREENSHOT to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to
+                R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to
+                R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_ALL_APPS to R.string.shortcut_helper_category_system_controls,
+            KEY_GESTURE_TYPE_OPEN_NOTES to R.string.shortcut_helper_category_system_apps,
+            KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to
+                R.string.shortcut_helper_category_system_apps,
+            KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.shortcut_helper_category_system_apps,
+            KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to
+                R.string.shortcut_helper_category_system_apps,
 
             // Multitasking Category
-            KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to "Recent apps",
-            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to "Split screen",
-            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to "Split screen",
-            KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to "Split screen",
-            KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to "Split screen",
-            KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to "Split screen",
+            KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to R.string.shortcutHelper_category_recent_apps,
+            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to
+                R.string.shortcutHelper_category_split_screen,
+            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to
+                R.string.shortcutHelper_category_split_screen,
+            KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to
+                R.string.shortcutHelper_category_split_screen,
+            KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to
+                R.string.shortcutHelper_category_split_screen,
+            KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to
+                R.string.shortcutHelper_category_split_screen,
 
             // App Category
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to "Applications",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to "Applications",
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to
+                R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to
+                R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to
+                R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to
+                R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to R.string.keyboard_shortcut_group_applications,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to
+                R.string.keyboard_shortcut_group_applications,
         )
 
     val gestureToInternalKeyboardShortcutInfoLabelMap =
         mapOf(
             // System Category
-            KEY_GESTURE_TYPE_HOME to "Go to home screen",
-            KEY_GESTURE_TYPE_RECENT_APPS to "View recent apps",
-            KEY_GESTURE_TYPE_BACK to "Go back",
-            KEY_GESTURE_TYPE_TAKE_SCREENSHOT to "Take screenshot",
-            KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to "Show shortcuts",
-            KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to "View notifications",
-            KEY_GESTURE_TYPE_LOCK_SCREEN to "Lock screen",
-            KEY_GESTURE_TYPE_ALL_APPS to "Open apps list",
-            KEY_GESTURE_TYPE_OPEN_NOTES to "Take a note",
-            KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to "Open settings",
-            KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to "Open assistant",
-            KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to "Open assistant",
+            KEY_GESTURE_TYPE_HOME to R.string.group_system_access_home_screen,
+            KEY_GESTURE_TYPE_RECENT_APPS to R.string.group_system_overview_open_apps,
+            KEY_GESTURE_TYPE_BACK to R.string.group_system_go_back,
+            KEY_GESTURE_TYPE_TAKE_SCREENSHOT to R.string.group_system_full_screenshot,
+            KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to
+                R.string.group_system_access_system_app_shortcuts,
+            KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to
+                R.string.group_system_access_notification_shade,
+            KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.group_system_lock_screen,
+            KEY_GESTURE_TYPE_ALL_APPS to R.string.group_system_access_all_apps_search,
+            KEY_GESTURE_TYPE_OPEN_NOTES to R.string.group_system_quick_memo,
+            KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to R.string.group_system_access_system_settings,
+            KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.group_system_access_google_assistant,
+            KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to
+                R.string.group_system_access_google_assistant,
 
             // Multitasking Category
-            KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to "Cycle forward through recent apps",
-            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to
-                "Use split screen with current app on the left",
-            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to
-                "Use split screen with current app on the right",
-            KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to "Switch from split screen to full screen",
+            KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER to R.string.group_system_cycle_forward,
+            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to R.string.system_multitasking_lhs,
+            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to R.string.system_multitasking_rhs,
+            KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to R.string.system_multitasking_full_screen,
             KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to
-                "Switch to app on left or above while using split screen",
+                R.string.system_multitasking_splitscreen_focus_lhs,
             KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to
-                "Switch to app on right or below while using split screen",
+                R.string.system_multitasking_splitscreen_focus_rhs,
 
             // App Category
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to "Calculator",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to "Calendar",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to "Chrome",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to "Contacts",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to "Gmail",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to "Maps",
-            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to "Messages",
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to
+                R.string.keyboard_shortcut_group_applications_calculator,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to
+                R.string.keyboard_shortcut_group_applications_calendar,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to
+                R.string.keyboard_shortcut_group_applications_browser,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to
+                R.string.keyboard_shortcut_group_applications_contacts,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to
+                R.string.keyboard_shortcut_group_applications_email,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to
+                R.string.keyboard_shortcut_group_applications_maps,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to
+                R.string.keyboard_shortcut_group_applications_sms,
         )
 }
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 5f8570c..bf7df7e 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
@@ -20,7 +20,9 @@
     val label: String,
     val commands: List<ShortcutCommand>,
     val icon: ShortcutIcon? = null,
-)
+) {
+    val containsCustomShortcutCommands: Boolean = commands.any { it.isCustom }
+}
 
 class ShortcutBuilder(private val label: String) {
     val commands = mutableListOf<ShortcutCommand>()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
index e4ccc2c..203228b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCustomizationRequestInfo.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.keyboard.shortcut.shared.model
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+sealed interface ShortcutCustomizationRequestInfo {
+    data class Add(
+        val label: String,
+        val categoryType: ShortcutCategoryType,
+        val subCategoryLabel: String,
+    ) : ShortcutCustomizationRequestInfo
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 02e206e..e44bfe3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -24,7 +24,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.ui.composable.AssignNewShortcutDialog
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
 import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel
@@ -59,8 +59,8 @@
         }
     }
 
-    fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) {
-        viewModel.onAddShortcutDialogRequested(shortcutBeingCustomized)
+    fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) {
+        viewModel.onShortcutCustomizationRequested(requestInfo)
     }
 
     private fun createAddShortcutDialog(): Dialog {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
index 10a201e..fa03883 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarter.kt
@@ -84,7 +84,7 @@
                     onKeyboardSettingsClicked = { onKeyboardSettingsClicked(dialog) },
                     onSearchQueryChanged = { shortcutHelperViewModel.onSearchQueryChanged(it) },
                     onCustomizationRequested = {
-                        shortcutCustomizationDialogStarter.onAddShortcutDialogRequested(it)
+                        shortcutCustomizationDialogStarter.onShortcutCustomizationRequested(it)
                     },
                 )
                 dialog.setOnDismissListener { shortcutHelperViewModel.onViewClosed() }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 13934ea..3666de4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -43,6 +43,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.lazy.rememberLazyListState
@@ -53,6 +54,7 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.automirrored.filled.OpenInNew
 import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.DeleteOutline
 import androidx.compose.material.icons.filled.ExpandMore
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material.icons.filled.Tune
@@ -70,8 +72,8 @@
 import androidx.compose.material3.Text
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -89,6 +91,7 @@
 import androidx.compose.ui.input.key.key
 import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
@@ -98,6 +101,7 @@
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.buildAnnotatedString
 import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
@@ -109,14 +113,15 @@
 import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 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.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutIcon
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
 import com.android.systemui.keyboard.shortcut.ui.model.IconSource
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
 import com.android.systemui.res.R
+import kotlinx.coroutines.delay
 
 @Composable
 fun ShortcutHelper(
@@ -125,7 +130,7 @@
     modifier: Modifier = Modifier,
     shortcutsUiState: ShortcutsUiState,
     useSinglePane: @Composable () -> Boolean = { shouldUseSinglePane() },
-    onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
 ) {
     when (shortcutsUiState) {
         is ShortcutsUiState.Active -> {
@@ -138,6 +143,7 @@
                 onCustomizationRequested,
             )
         }
+
         else -> {
             // No-op for now.
         }
@@ -151,7 +157,7 @@
     onSearchQueryChanged: (String) -> Unit,
     modifier: Modifier,
     onKeyboardSettingsClicked: () -> Unit,
-    onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
 ) {
     var selectedCategoryType by
         remember(shortcutsUiState.defaultSelectedCategory) {
@@ -367,26 +373,26 @@
     onCategorySelected: (ShortcutCategoryType?) -> Unit,
     onKeyboardSettingsClicked: () -> Unit,
     isShortcutCustomizerFlagEnabled: Boolean,
-    onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
 ) {
     val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
-    var isCustomizeModeEntered by remember { mutableStateOf(false) }
-    val isCustomizing by
-        remember(isCustomizeModeEntered, isShortcutCustomizerFlagEnabled) {
-            derivedStateOf { isCustomizeModeEntered && isCustomizeModeEntered }
-        }
+    var isCustomizing by remember { mutableStateOf(false) }
 
     Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) {
         Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
-            Box(modifier = Modifier.padding(start = 202.dp).width(412.dp)) {
-                TitleBar(isCustomizing)
-            }
-            Spacer(modifier = Modifier.weight(1f))
-            if (isShortcutCustomizerFlagEnabled) {
-                if (isCustomizeModeEntered) {
-                    DoneButton(onClick = { isCustomizeModeEntered = false })
+            // Keep title centered whether customize button is visible or not.
+            Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) {
+                Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
+                    TitleBar(isCustomizing)
+                }
+                if (isShortcutCustomizerFlagEnabled) {
+                    if (isCustomizing) {
+                        DoneButton(onClick = { isCustomizing = false })
+                    } else {
+                        CustomizeButton(onClick = { isCustomizing = true })
+                    }
                 } else {
-                    CustomizeButton(onClick = { isCustomizeModeEntered = true })
+                    Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp))
                 }
             }
         }
@@ -441,7 +447,7 @@
     modifier: Modifier,
     category: ShortcutCategoryUi?,
     isCustomizing: Boolean,
-    onCustomizationRequested: (ShortcutInfo) -> Unit = {},
+    onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
 ) {
     val listState = rememberLazyListState()
     LaunchedEffect(key1 = category) { if (category != null) listState.animateScrollToItem(0) }
@@ -457,7 +463,7 @@
                 isCustomizing = isCustomizing,
                 onCustomizationRequested = { label, subCategoryLabel ->
                     onCustomizationRequested(
-                        ShortcutInfo(
+                        ShortcutCustomizationRequestInfo.Add(
                             label = label,
                             subCategoryLabel = subCategoryLabel,
                             categoryType = category.type,
@@ -551,7 +557,7 @@
             .padding(8.dp)
     ) {
         Row(
-            modifier = Modifier.width(128.dp).align(Alignment.CenterVertically),
+            modifier = Modifier.width(128.dp).align(Alignment.CenterVertically).weight(0.333f),
             horizontalArrangement = Arrangement.spacedBy(16.dp),
             verticalAlignment = Alignment.CenterVertically,
         ) {
@@ -562,10 +568,10 @@
         }
         Spacer(modifier = Modifier.width(24.dp))
         ShortcutKeyCombinations(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(.666f),
             shortcut = shortcut,
             isCustomizing = isCustomizing,
-            onAddShortcutClicked = { onCustomizationRequested(shortcut.label) },
+            onAddShortcutRequested = { onCustomizationRequested(shortcut.label) },
         )
     }
 }
@@ -594,42 +600,92 @@
     modifier: Modifier = Modifier,
     shortcut: ShortcutModel,
     isCustomizing: Boolean = false,
-    onAddShortcutClicked: () -> Unit = {},
+    onAddShortcutRequested: () -> Unit = {},
+    onDeleteShortcutRequested: () -> Unit = {},
 ) {
     FlowRow(
         modifier = modifier,
         verticalArrangement = Arrangement.spacedBy(8.dp),
+        itemVerticalAlignment = Alignment.CenterVertically,
         horizontalArrangement = Arrangement.End,
     ) {
         shortcut.commands.forEachIndexed { index, command ->
             if (index > 0) {
                 ShortcutOrSeparator(spacing = 16.dp)
             }
-            ShortcutCommand(command)
+            ShortcutCommandContainer(showBackground = command.isCustom) { ShortcutCommand(command) }
         }
         if (isCustomizing) {
             Spacer(modifier = Modifier.width(16.dp))
-            ShortcutHelperButton(
-                modifier =
-                    Modifier.border(
-                        width = 1.dp,
-                        color = MaterialTheme.colorScheme.outline,
-                        shape = CircleShape,
-                    ),
-                onClick = { onAddShortcutClicked() },
-                color = Color.Transparent,
-                width = 32.dp,
-                height = 32.dp,
-                iconSource = IconSource(imageVector = Icons.Default.Add),
-                contentColor = MaterialTheme.colorScheme.primary,
-                contentPaddingVertical = 0.dp,
-                contentPaddingHorizontal = 0.dp,
-            )
+            if (shortcut.containsCustomShortcutCommands) {
+                DeleteShortcutButton(onDeleteShortcutRequested)
+            } else {
+                AddShortcutButton(onAddShortcutRequested)
+            }
         }
     }
 }
 
 @Composable
+private fun AddShortcutButton(onClick: () -> Unit) {
+    ShortcutHelperButton(
+        modifier =
+            Modifier.border(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.outline,
+                shape = CircleShape,
+            ),
+        onClick = onClick,
+        color = Color.Transparent,
+        width = 32.dp,
+        height = 32.dp,
+        iconSource = IconSource(imageVector = Icons.Default.Add),
+        contentColor = MaterialTheme.colorScheme.primary,
+        contentPaddingVertical = 0.dp,
+        contentPaddingHorizontal = 0.dp,
+    )
+}
+
+@Composable
+private fun DeleteShortcutButton(onClick: () -> Unit) {
+    ShortcutHelperButton(
+        modifier =
+            Modifier.border(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.outline,
+                shape = CircleShape,
+            ),
+        onClick = onClick,
+        color = Color.Transparent,
+        width = 32.dp,
+        height = 32.dp,
+        iconSource = IconSource(imageVector = Icons.Default.DeleteOutline),
+        contentColor = MaterialTheme.colorScheme.primary,
+        contentPaddingVertical = 0.dp,
+        contentPaddingHorizontal = 0.dp,
+    )
+}
+
+@Composable
+private fun ShortcutCommandContainer(showBackground: Boolean, content: @Composable () -> Unit) {
+    if (showBackground) {
+        Box(
+            modifier =
+                Modifier.wrapContentSize()
+                    .background(
+                        color = MaterialTheme.colorScheme.outlineVariant,
+                        shape = RoundedCornerShape(16.dp),
+                    )
+                    .padding(4.dp)
+        ) {
+            content()
+        }
+    } else {
+        content()
+    }
+}
+
+@Composable
 private fun ShortcutCommand(command: ShortcutCommand) {
     Row {
         command.keys.forEachIndexed { keyIndex, key ->
@@ -742,16 +798,25 @@
     selectedCategory: ShortcutCategoryType?,
     onCategoryClicked: (ShortcutCategoryUi) -> Unit,
 ) {
-    Column(modifier) {
-        ShortcutsSearchBar(onSearchQueryChanged)
-        Spacer(modifier = Modifier.heightIn(8.dp))
-        CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked)
-        Spacer(modifier = Modifier.weight(1f))
-        KeyboardSettings(
-            horizontalPadding = 24.dp,
-            verticalPadding = 24.dp,
-            onKeyboardSettingsClicked,
-        )
+    CompositionLocalProvider(
+        // Restrict system font scale increases up to a max so categories display correctly.
+        LocalDensity provides
+            Density(
+                density = LocalDensity.current.density,
+                fontScale = LocalDensity.current.fontScale.coerceIn(1f, 1.5f),
+            )
+    ) {
+        Column(modifier) {
+            ShortcutsSearchBar(onSearchQueryChanged)
+            Spacer(modifier = Modifier.heightIn(8.dp))
+            CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked)
+            Spacer(modifier = Modifier.weight(1f))
+            KeyboardSettings(
+                horizontalPadding = 24.dp,
+                verticalPadding = 24.dp,
+                onKeyboardSettingsClicked,
+            )
+        }
     }
 }
 
@@ -853,7 +918,12 @@
     var queryInternal by remember { mutableStateOf("") }
     val focusRequester = remember { FocusRequester() }
     val focusManager = LocalFocusManager.current
-    LaunchedEffect(Unit) { focusRequester.requestFocus() }
+    LaunchedEffect(Unit) {
+        // TODO(b/272065229): Added minor delay so TalkBack can take focus of search box by default,
+        //  remove when default a11y focus is fixed.
+        delay(50)
+        focusRequester.requestFocus()
+    }
     SearchBar(
         modifier =
             Modifier.fillMaxWidth().focusRequester(focusRequester).onKeyEvent {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
index e295564..f9904f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt
@@ -49,5 +49,5 @@
 object ShortcutHelperBottomSheet {
     val DefaultWidth = 412.dp
     val LargeScreenWidthPortrait = 704.dp
-    val LargeScreenWidthLandscape = 864.dp
+    val LargeScreenWidthLandscape = 960.dp
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
index e761c73..58ce194 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.IndicationNodeFactory
+import androidx.compose.foundation.LocalIndication
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.clickable
@@ -126,8 +127,7 @@
                     .selectable(
                         selected = selected,
                         interactionSource = interactionSource,
-                        indication =
-                            ShortcutHelperIndication(interactionSource, interactionsConfig),
+                        indication = ShortcutHelperIndication(interactionsConfig),
                         enabled = enabled,
                         onClick = onClick,
                     )
@@ -181,8 +181,7 @@
                     )
                     .clickable(
                         interactionSource = interactionSource,
-                        indication =
-                            ShortcutHelperIndication(interactionSource, interactionsConfig),
+                        indication = ShortcutHelperIndication(interactionsConfig),
                         enabled = enabled,
                         onClick = onClick,
                     ),
@@ -507,10 +506,8 @@
     }
 }
 
-data class ShortcutHelperIndication(
-    private val interactionSource: InteractionSource,
-    private val interactionsConfig: InteractionsConfig,
-) : IndicationNodeFactory {
+data class ShortcutHelperIndication(private val interactionsConfig: InteractionsConfig) :
+    IndicationNodeFactory {
     override fun create(interactionSource: InteractionSource): DelegatableNode {
         return ShortcutHelperInteractionsNode(interactionSource, interactionsConfig)
     }
@@ -529,3 +526,15 @@
     val hoverPadding: Dp = 0.dp,
     val pressedPadding: Dp = hoverPadding,
 )
+
+@Composable
+fun ProvideShortcutHelperIndication(
+    interactionsConfig: InteractionsConfig,
+    content: @Composable () -> Unit,
+) {
+    CompositionLocalProvider(
+        LocalIndication provides ShortcutHelperIndication(interactionsConfig)
+    ) {
+        content()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index b925387..e86da5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -19,7 +19,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.input.key.KeyEvent
 import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -30,32 +30,35 @@
 class ShortcutCustomizationViewModel
 @AssistedInject
 constructor(private val shortcutCustomizationInteractor: ShortcutCustomizationInteractor) {
-    private val _shortcutBeingCustomized = mutableStateOf<ShortcutInfo?>(null)
+    private val _shortcutBeingCustomized = mutableStateOf<ShortcutCustomizationRequestInfo?>(null)
 
     private val _shortcutCustomizationUiState =
         MutableStateFlow<ShortcutCustomizationUiState>(ShortcutCustomizationUiState.Inactive)
 
     val shortcutCustomizationUiState = _shortcutCustomizationUiState.asStateFlow()
 
-    fun onAddShortcutDialogRequested(shortcutBeingCustomized: ShortcutInfo) {
-        _shortcutCustomizationUiState.value =
-            ShortcutCustomizationUiState.AddShortcutDialog(
-                shortcutLabel = shortcutBeingCustomized.label,
-                shouldShowErrorMessage = false,
-                isValidKeyCombination = false,
-                defaultCustomShortcutModifierKey =
-                    shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
-                isDialogShowing = false,
-            )
-
-        _shortcutBeingCustomized.value = shortcutBeingCustomized
+    fun onShortcutCustomizationRequested(requestInfo: ShortcutCustomizationRequestInfo) {
+        when (requestInfo) {
+            is ShortcutCustomizationRequestInfo.Add -> {
+                _shortcutCustomizationUiState.value =
+                    ShortcutCustomizationUiState.AddShortcutDialog(
+                        shortcutLabel = requestInfo.label,
+                        shouldShowErrorMessage = false,
+                        isValidKeyCombination = false,
+                        defaultCustomShortcutModifierKey =
+                            shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
+                        isDialogShowing = false,
+                    )
+                _shortcutBeingCustomized.value = requestInfo
+            }
+        }
     }
 
     fun onAddShortcutDialogShown() {
         _shortcutCustomizationUiState.update { uiState ->
-            (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)
-                ?.let { it.copy(isDialogShowing = true) }
-                ?: uiState
+            (uiState as? ShortcutCustomizationUiState.AddShortcutDialog)?.copy(
+                isDialogShowing = true
+            ) ?: uiState
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 2d05600..5ec6d37 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -95,7 +95,7 @@
     private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
     private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
     @ShadeDisplayAware private val configuration: ConfigurationState,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val keyguardIndicationController: KeyguardIndicationController,
     private val shadeInteractor: ShadeInteractor,
     private val interactionJankMonitor: InteractionJankMonitor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2ee9ddb..01ec4d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2875,7 +2875,7 @@
             }
 
             if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
-                mKeyguardTransitions.startKeyguardTransition(showing, aodShowing);
+                startKeyguardTransition(showing, aodShowing);
             } else {
                 try {
 
@@ -3019,7 +3019,7 @@
                 final int keyguardFlag = flags;
                 mUiBgExecutor.execute(() -> {
                     if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
-                        mKeyguardTransitions.startKeyguardTransition(
+                        startKeyguardTransition(
                                 false /* keyguardShowing */, false /* aodShowing */);
                         return;
                     }
@@ -3035,6 +3035,10 @@
         }
     };
 
+    private void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) {
+        mKeyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing);
+    }
+
     private final Runnable mHideAnimationFinishedRunnable = () -> {
         Log.e(TAG, "mHideAnimationFinishedRunnable#run");
         mHideAnimationRunning = false;
@@ -3490,8 +3494,7 @@
         mSurfaceBehindRemoteAnimationRequested = true;
 
         if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) {
-            mKeyguardTransitions.startKeyguardTransition(
-                    false /* keyguardShowing */, false /* aodShowing */);
+            startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
index 39144b5..c0ffda6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WakefulnessLifecycle.java
@@ -34,6 +34,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.util.time.SystemClock;
 
 import java.io.PrintWriter;
@@ -91,7 +92,7 @@
 
     @Inject
     public WakefulnessLifecycle(
-            Context context,
+            @ShadeDisplayAware Context context,
             @Nullable IWallpaperManager wallpaperManagerService,
             SystemClock systemClock,
             DumpManager dumpManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 2914cb9..a137d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -122,10 +122,7 @@
 
         if (visible) {
             if (enableNewKeyguardShellTransitions) {
-                keyguardTransitions.startKeyguardTransition(
-                    false /* keyguardShowing */,
-                    false, /* aodShowing */
-                )
+                startKeyguardTransition(false, /* keyguardShowing */ false /* aodShowing */)
                 isKeyguardGoingAway = true
                 return
             }
@@ -233,7 +230,7 @@
                 "aodVisible=$aodVisible).",
         )
         if (enableNewKeyguardShellTransitions) {
-            keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible)
+            startKeyguardTransition(lockscreenShowing, aodVisible)
         } else {
             activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible)
         }
@@ -241,6 +238,10 @@
         this.isAodVisible = aodVisible
     }
 
+    private fun startKeyguardTransition(keyguardShowing: Boolean, aodShowing: Boolean) {
+        keyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing)
+    }
+
     private fun endKeyguardGoingAwayAnimation() {
         if (!isKeyguardGoingAway) {
             Log.d(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
index 585bd6a..4bac8f7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
@@ -46,6 +46,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
@@ -83,7 +84,7 @@
     val activityTransitionAnimator: ActivityTransitionAnimator,
     val keyguardViewController: dagger.Lazy<KeyguardViewController>,
     val powerInteractor: PowerInteractor,
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     val interactionJankMonitor: InteractionJankMonitor,
     @Main executor: Executor,
     val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 7638079..0101e09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -68,6 +68,7 @@
 import com.android.systemui.process.ProcessWrapper;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -126,7 +127,7 @@
     @Provides
     @SysUISingleton
     static KeyguardViewMediator newKeyguardViewMediator(
-            Context context,
+            @ShadeDisplayAware Context context,
             UiEventLogger uiEventLogger,
             SessionTracker sessionTracker,
             UserTracker userTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index 77e8179..74ee052 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -27,9 +27,9 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -41,7 +41,7 @@
 class CameraQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val packageManager: PackageManager,
     private val cameraGestureHelper: Lazy<CameraGestureHelper>,
     private val userTracker: UserTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
index be87334..d1f9fa2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.modes.shared.ModesUi
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.ZenModeController
 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.util.settings.SecureSettings
@@ -75,7 +76,7 @@
 
     @Inject
     constructor(
-        context: Context,
+        @ShadeDisplayAware context: Context,
         controller: ZenModeController,
         interactor: ZenModeInteractor,
         secureSettings: SecureSettings,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
index a7999c1..480ef5e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.FlashlightController
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
@@ -36,7 +37,7 @@
 class FlashlightQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val flashlightController: FlashlightController,
 ) : KeyguardQuickAffordanceConfig {
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index cc36961..3555f06 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.Companion.appStoreIntent
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.kotlin.getOrNull
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
@@ -48,7 +49,7 @@
 class HomeControlsKeyguardQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val component: ControlsComponent,
 ) : KeyguardQuickAffordanceConfig {
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
index 796374a..f08576a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
@@ -47,7 +48,7 @@
 class KeyguardQuickAffordanceLocalUserSelectionManager
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val userFileManager: UserFileManager,
     private val userTracker: UserTracker,
     broadcastDispatcher: BroadcastDispatcher,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
index 6c1bdad..1358634 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.RingerModeTracker
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -51,7 +52,7 @@
 class MuteQuickAffordanceConfig
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val userTracker: UserTracker,
     private val userFileManager: UserFileManager,
     private val ringerModeTracker: RingerModeTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index a503541..d12c42a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
@@ -36,7 +37,7 @@
 class QrCodeScannerKeyguardQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val controller: QRCodeScannerController,
 ) : KeyguardQuickAffordanceConfig {
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 56b520e..eafa1ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.wallet.controller.QuickAccessWalletController
 import com.android.systemui.wallet.util.getPaymentCards
 import javax.inject.Inject
@@ -51,7 +52,7 @@
 class QuickAccessWalletKeyguardQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val walletController: QuickAccessWalletController,
     private val activityStarter: ActivityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
index 3e6e3b7..ceaeeca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/VideoCameraQuickAffordanceConfig.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.Flow
@@ -42,7 +43,7 @@
 class VideoCameraQuickAffordanceConfig
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val cameraIntents: CameraIntentsWrapper,
     private val activityIntentHelper: ActivityIntentHelper,
     private val userTracker: UserTracker,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
index dd3e619..ab8cc71 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepository.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.keyguard.shared.model.AuthenticationFlags
 import com.android.systemui.keyguard.shared.model.DevicePosture
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
 import com.android.systemui.user.data.repository.UserRepository
 import java.io.PrintWriter
@@ -123,7 +124,7 @@
 class BiometricSettingsRepositoryImpl
 @Inject
 constructor(
-    context: Context,
+    @ShadeDisplayAware context: Context,
     lockPatternUtils: LockPatternUtils,
     broadcastDispatcher: BroadcastDispatcher,
     authController: AuthController,
@@ -354,7 +355,10 @@
 }
 
 @OptIn(ExperimentalCoroutinesApi::class)
-private class StrongAuthTracker(private val userRepository: UserRepository, context: Context?) :
+private class StrongAuthTracker(
+    private val userRepository: UserRepository,
+    @ShadeDisplayAware context: Context?
+) :
     LockPatternUtils.StrongAuthTracker(context) {
 
     private val selectedUserId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
index be4ab4b..c9be207 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepository.kt
@@ -19,7 +19,6 @@
 import android.annotation.IntDef
 import android.content.res.Resources
 import android.provider.Settings
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -27,13 +26,11 @@
 import com.android.systemui.keyguard.shared.model.DevicePosture
 import com.android.systemui.keyguard.shared.model.DevicePosture.UNKNOWN
 import com.android.systemui.res.R
-import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.kotlin.FlowDumperImpl
+import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
@@ -48,7 +45,7 @@
     biometricSettingsRepository: BiometricSettingsRepository,
     devicePostureRepository: DevicePostureRepository,
     dumpManager: DumpManager,
-    private val tunerService: TunerService,
+    secureSettingsRepository: UserAwareSecureSettingsRepository,
     @Background backgroundDispatcher: CoroutineDispatcher,
 ) : FlowDumperImpl(dumpManager) {
 
@@ -61,40 +58,26 @@
         DevicePosture.toPosture(resources.getInteger(R.integer.config_face_auth_supported_posture))
     }
 
-    private val dismissByDefault: Int by lazy {
-        if (resources.getBoolean(com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) {
-            1
-        } else {
-            0
-        }
-    }
-
     private var bypassEnabledSetting: Flow<Boolean> =
-        callbackFlow {
-                val updateBypassSetting = { state: Boolean ->
-                    trySendWithFailureLogging(state, TAG, "Error sending bypassSetting $state")
-                }
-
-                val tunable =
-                    TunerService.Tunable { key, _ ->
-                        updateBypassSetting(tunerService.getValue(key, dismissByDefault) != 0)
-                    }
-
-                updateBypassSetting(false)
-                tunerService.addTunable(tunable, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
-                awaitClose { tunerService.removeTunable(tunable) }
-            }
+        secureSettingsRepository
+            .boolSetting(
+                name = Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+                defaultValue =
+                    resources.getBoolean(
+                        com.android.internal.R.bool.config_faceAuthDismissesKeyguard
+                    ),
+            )
             .flowOn(backgroundDispatcher)
             .dumpWhileCollecting("bypassEnabledSetting")
 
-    val overrideFaceBypassSetting: Flow<Boolean> =
+    private val overrideFaceBypassSetting: Flow<Boolean> =
         when (bypassOverride) {
             FACE_UNLOCK_BYPASS_ALWAYS -> flowOf(true)
             FACE_UNLOCK_BYPASS_NEVER -> flowOf(false)
             else -> bypassEnabledSetting
         }
 
-    val isPostureAllowedForFaceAuth: Flow<Boolean> =
+    private val isPostureAllowedForFaceAuth: Flow<Boolean> =
         when (configFaceAuthSupportedPosture) {
             UNKNOWN -> flowOf(true)
             else ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 95d1b5d..9718e75 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.plugins.clocks.ClockId
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
@@ -89,7 +90,7 @@
     override val clockEventController: ClockEventController,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     @Application private val applicationScope: CoroutineScope,
-    @Application private val applicationContext: Context,
+    @ShadeDisplayAware private val context: Context,
     private val featureFlags: FeatureFlagsClassic,
 ) : KeyguardClockRepository {
 
@@ -143,7 +144,7 @@
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = clockRegistry.createCurrentClock(),
+                initialValue = null,
             )
 
     override val previewClock: Flow<ClockController> =
@@ -166,7 +167,7 @@
         get() =
             featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) &&
                 // True on small landscape screens
-                applicationContext.resources.getBoolean(R.bool.force_small_clock_on_lockscreen)
+                context.resources.getBoolean(R.bool.force_small_clock_on_lockscreen)
 
     private fun getClockSize(): ClockSizeSetting {
         return ClockSizeSetting.fromSettingValue(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
index d0de21b..c1ec88b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.kotlin.FlowDumperImpl
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -57,7 +58,7 @@
 class KeyguardQuickAffordanceRepository
 @Inject
 constructor(
-    @Application private val appContext: Context,
+    @ShadeDisplayAware private val appContext: Context,
     @Application private val scope: CoroutineScope,
     private val localUserSelectionManager: KeyguardQuickAffordanceLocalUserSelectionManager,
     private val remoteUserSelectionManager: KeyguardQuickAffordanceRemoteUserSelectionManager,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
index b67fd4b..549a508 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard.data.repository
 
-import android.content.Context
 import android.os.UserHandle
 import android.provider.Settings
 import android.view.View
@@ -46,7 +45,6 @@
 class KeyguardSmartspaceRepositoryImpl
 @Inject
 constructor(
-    context: Context,
     private val secureSettings: SecureSettings,
     private val userTracker: UserTracker,
     @Application private val applicationScope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index eaf8fa9..354fc3d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -305,12 +305,12 @@
     }
 
     override suspend fun forceFinishCurrentTransition() {
-        withContextMutex.lock()
-
         if (lastAnimator?.isRunning != true) {
             return
         }
 
+        withContextMutex.lock()
+
         return withContext("$TAG#forceFinishCurrentTransition", mainDispatcher) {
             withContextMutex.unlock()
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
index 4c9c282..4f6319a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakeSleepReason.TAP
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.CircleReveal
 import com.android.systemui.statusbar.LiftReveal
 import com.android.systemui.statusbar.LightRevealEffect
@@ -77,7 +78,7 @@
 @Inject
 constructor(
     keyguardRepository: KeyguardRepository,
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     powerRepository: PowerRepository,
     private val scrimLogger: ScrimLogger,
 ) : LightRevealScrimRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
index 73a4cc3..68ec4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractor.kt
@@ -45,7 +45,7 @@
 class BurnInInteractor
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val burnInHelperWrapper: BurnInHelperWrapper,
     @Application private val scope: CoroutineScope,
     @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index 03cf1a4..6367b5c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -47,7 +48,7 @@
 class DeviceEntrySideFpsOverlayInteractor
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
     private val sceneInteractor: SceneInteractor,
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index d4d7e75..2d81be6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import javax.inject.Inject
@@ -39,7 +40,7 @@
 class KeyguardKeyEventInteractor
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val statusBarStateController: StatusBarStateController,
     private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
     private val shadeController: ShadeController,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 8c9473f..ae55825 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -51,6 +51,7 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
 import com.android.systemui.shared.quickaffordance.shared.model.KeyguardPreviewConstants.KEYGUARD_QUICK_AFFORDANCE_ID_NONE
@@ -90,7 +91,7 @@
     private val dockManager: DockManager,
     private val biometricSettingsRepository: BiometricSettingsRepository,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
-    @Application private val appContext: Context,
+    @ShadeDisplayAware private val appContext: Context,
     private val sceneInteractor: Lazy<SceneInteractor>,
 ) {
     /**
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 377a03e..b9784f1 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
@@ -23,6 +23,7 @@
 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.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.util.kotlin.sample
 import com.android.systemui.util.kotlin.toPx
@@ -45,7 +46,7 @@
 @Inject
 constructor(
     private val repository: KeyguardSurfaceBehindRepository,
-    context: Context,
+    @ShadeDisplayAware context: Context,
     transitionInteractor: KeyguardTransitionInteractor,
     inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>,
     swipeToDismissInteractor: SwipeToDismissInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
index b2031d3..274a1dd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTouchHandlingInteractor.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.res.R
 import com.android.systemui.shade.PulsingGestureListener
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -58,7 +59,7 @@
 class KeyguardTouchHandlingInteractor
 @Inject
 constructor(
-    @Application private val appContext: Context,
+    @ShadeDisplayAware private val context: Context,
     @Application private val scope: CoroutineScope,
     transitionInteractor: KeyguardTransitionInteractor,
     repository: KeyguardRepository,
@@ -188,7 +189,7 @@
 
     private fun isFeatureEnabled(): Boolean {
         return featureFlags.isEnabled(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED) &&
-            appContext.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled)
+            context.resources.getBoolean(R.bool.long_press_keyguard_customize_lockscreen_enabled)
     }
 
     /** Updates application state to ask to show the menu. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
index 9c98a96..fbc7e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.kotlin.sample
 import com.android.systemui.util.settings.SecureSettings
@@ -75,7 +76,7 @@
 @Inject
 constructor(
     @Application private val scope: CoroutineScope,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val repository: KeyguardRepository,
     private val systemClock: SystemClock,
     private val alarmManager: AlarmManager,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
index 508fb59..7e77423 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NaturalScrollingSettingObserver.kt
@@ -24,6 +24,7 @@
 import android.provider.Settings.SettingNotFoundException
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 
 @SysUISingleton
@@ -31,7 +32,7 @@
 @Inject
 constructor(
     @Main private val handler: Handler,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
 ) {
     var isNaturalScrollingEnabled = true
         get() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
index 73e80ff..d6a110a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessModel
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -62,7 +63,7 @@
 @Inject
 constructor(
     @Application private val scope: CoroutineScope,
-    @Application private val applicationContext: Context,
+    @ShadeDisplayAware private val context: Context,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
     private val statusBarService: IStatusBarService,
@@ -142,7 +143,7 @@
 
         scope.launch {
             disableFlagsForUserId.collect { (selectedUserId, flags) ->
-                if (applicationContext.getSystemService(Context.STATUS_BAR_SERVICE) == null) {
+                if (context.getSystemService(Context.STATUS_BAR_SERVICE) == null) {
                     return@collect
                 }
 
@@ -151,7 +152,7 @@
                         statusBarService.disableForUser(
                             flags,
                             disableToken,
-                            applicationContext.packageName,
+                            context.packageName,
                             selectedUserId,
                         )
                     } catch (e: RemoteException) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
index 3540a0c..b6aa209 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/SwipeUpAnywhereGestureHandler.kt
@@ -20,6 +20,7 @@
 import android.view.MotionEvent
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.gesture.SwipeUpGestureHandler
 import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
 import javax.inject.Inject
@@ -29,7 +30,7 @@
 class SwipeUpAnywhereGestureHandler
 @Inject
 constructor(
-    context: Context,
+    @ShadeDisplayAware context: Context,
     displayTracker: DisplayTracker,
     logger: SwipeUpGestureLogger,
 ) :
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 914fdd2..6c03b24 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -151,7 +151,5 @@
         cs.applyTo(rootView)
     }
 
-    private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
-    private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
     private const val TAG = "KeyguardPreviewClockViewBinder"
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
index 717a898..587a8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AccessibilityActionsSection.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.ui.binder.AccessibilityActionsViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.AccessibilityActionsViewModel
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.Utils
 import javax.inject.Inject
 import kotlinx.coroutines.DisposableHandle
@@ -37,7 +38,7 @@
 class AccessibilityActionsSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val communalSettingsInteractor: CommunalSettingsInteractor,
     private val accessibilityActionsViewModel: AccessibilityActionsViewModel,
 ) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
index d639978..8622ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt
@@ -28,13 +28,14 @@
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 
 /** Adds a layer to group elements for translation for burn-in preventation */
 class AodBurnInSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val rootView: KeyguardRootView,
     private val clockViewModel: KeyguardClockViewModel,
 ) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index faa4978..4c23adf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -29,6 +29,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
@@ -47,7 +48,7 @@
 class AodNotificationIconsSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @ShadeDisplayAware private val configurationState: ConfigurationState,
     private val iconBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
     private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
@@ -114,14 +115,14 @@
                 START,
                 PARENT_ID,
                 START,
-                context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+                context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal),
             )
             connect(
                 nicId,
                 END,
                 PARENT_ID,
                 END,
-                context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+                context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal),
             )
             constrainHeight(
                 nicId,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 6096cf7..6c98d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.clocks.ClockFaceLayout
 import com.android.systemui.res.R
 import com.android.systemui.shade.LargeScreenHeaderHelper
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.util.ui.value
 import dagger.Lazy
@@ -69,7 +70,7 @@
 constructor(
     private val clockInteractor: KeyguardClockInteractor,
     protected val keyguardClockViewModel: KeyguardClockViewModel,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     val smartspaceViewModel: KeyguardSmartspaceViewModel,
     val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
     private val rootViewModel: KeyguardRootViewModel,
@@ -220,7 +221,9 @@
                 PARENT_ID,
                 START,
                 context.resources.getDimensionPixelSize(customR.dimen.clock_padding_start) +
-                    context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
+                    context.resources.getDimensionPixelSize(
+                        customR.dimen.status_view_margin_horizontal
+                    ),
             )
             val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin()
             create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 8d2bfb5..b51bb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
@@ -60,7 +61,7 @@
     @Application private val applicationScope: CoroutineScope,
     private val authController: AuthController,
     private val windowManager: WindowManager,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val notificationPanelView: NotificationPanelView,
     private val featureFlags: FeatureFlags,
     private val deviceEntryIconViewModel: Lazy<DeviceEntryIconViewModel>,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
index af0528a..2d9dac4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.KeyguardIndicationController
 import javax.inject.Inject
 import kotlinx.coroutines.DisposableHandle
@@ -34,7 +35,7 @@
 class DefaultIndicationAreaSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel,
     private val indicationController: KeyguardIndicationController,
 ) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index 6ac33af..3a791fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -38,7 +39,7 @@
 class DefaultNotificationStackScrollLayoutSection
 @Inject
 constructor(
-    context: Context,
+    @ShadeDisplayAware context: Context,
     notificationPanelView: NotificationPanelView,
     sharedNotificationContainer: SharedNotificationContainer,
     sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
index 9b5fae3..9d9be44 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusBarSection.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.ShadeViewStateProvider
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView
 import com.android.systemui.util.Utils
@@ -40,7 +41,7 @@
 class DefaultStatusBarSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val notificationPanelView: NotificationPanelView,
     private val keyguardStatusBarViewComponentFactory: KeyguardStatusBarViewComponent.Factory,
 ) : KeyguardSection() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index 45641db..57ea1ad 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.util.Utils
 import dagger.Lazy
@@ -47,7 +48,7 @@
 class DefaultStatusViewSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val notificationPanelView: NotificationPanelView,
     private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
     private val keyguardViewConfigurator: Lazy<KeyguardViewConfigurator>,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
index 2abb7ba..0ae1400 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultUdfpsAccessibilityOverlaySection.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -34,7 +35,7 @@
 class DefaultUdfpsAccessibilityOverlaySection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val viewModel: DeviceEntryUdfpsAccessibilityOverlayViewModel,
 ) : KeyguardSection() {
     private val viewId = R.id.udfps_accessibility_overlay
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 6ddcae3..7ad2ec5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.keyguard.ui.binder.KeyguardSmartspaceViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.res.R as R
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
@@ -44,7 +45,7 @@
 open class SmartspaceSection
 @Inject
 constructor(
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     val keyguardClockViewModel: KeyguardClockViewModel,
     val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
     private val keyguardSmartspaceInteractor: KeyguardSmartspaceInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
index 5dbba75..f0d21f2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
@@ -28,20 +28,22 @@
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.shared.model.KeyguardSection
 import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 
 /** Aligns media on left side for split shade, below smartspace, date, and weather. */
 class SplitShadeMediaSection
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val notificationPanelView: NotificationPanelView,
-    private val keyguardMediaController: KeyguardMediaController
+    private val keyguardMediaController: KeyguardMediaController,
 ) : KeyguardSection() {
     private val mediaContainerId = R.id.status_view_media_container
 
@@ -61,7 +63,7 @@
                 val horizontalPadding =
                     padding +
                         context.resources.getDimensionPixelSize(
-                            R.dimen.status_view_margin_horizontal
+                            customR.dimen.status_view_margin_horizontal
                         )
 
                 setPaddingRelative(horizontalPadding, padding, horizontalPadding, padding)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 1a73866..729759a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
@@ -35,7 +36,7 @@
 class SplitShadeNotificationStackScrollLayoutSection
 @Inject
 constructor(
-    context: Context,
+    @ShadeDisplayAware context: Context,
     notificationPanelView: NotificationPanelView,
     sharedNotificationContainer: SharedNotificationContainer,
     sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
index 56e3125..3a5263f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
@@ -41,7 +41,7 @@
 class AlternateBouncerUdfpsIconViewModel
 @Inject
 constructor(
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
     deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     deviceEntryBackgroundViewModel: DeviceEntryBackgroundViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 12f9467..29ae4b9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -40,7 +40,7 @@
 class DeviceEntryBackgroundViewModel
 @Inject
 constructor(
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     val deviceEntryIconViewModel: DeviceEntryIconViewModel,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 749f193..5065fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -45,7 +45,7 @@
 class DeviceEntryForegroundViewModel
 @Inject
 constructor(
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
     deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     transitionInteractor: KeyguardTransitionInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index e30ddc6..de0927e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import android.content.Context
+import com.android.systemui.customization.R as customR
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
@@ -59,10 +60,9 @@
 
     /** Whether the weather area should be visible. */
     val isWeatherVisible: StateFlow<Boolean> =
-        combine(
+        combine(isWeatherEnabled, keyguardClockViewModel.hasCustomWeatherDataDisplay) {
                 isWeatherEnabled,
-                keyguardClockViewModel.hasCustomWeatherDataDisplay,
-            ) { isWeatherEnabled, clockIncludesCustomWeatherDisplay ->
+                clockIncludesCustomWeatherDisplay ->
                 isWeatherVisible(
                     clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay,
                     isWeatherEnabled = isWeatherEnabled,
@@ -76,7 +76,7 @@
                         clockIncludesCustomWeatherDisplay =
                             keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
                         isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
-                    )
+                    ),
             )
 
     private fun isWeatherVisible(
@@ -92,12 +92,12 @@
     companion object {
         fun getSmartspaceStartMargin(context: Context): Int {
             return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) +
-                context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+                context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
         }
 
         fun getSmartspaceEndMargin(context: Context): Int {
             return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) +
-                context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+                context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index da96f3f..3de1f1e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.phone.DozeServiceHost
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -66,7 +67,7 @@
 class SideFpsProgressBarViewModel
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     biometricStatusInteractor: BiometricStatusInteractor,
     deviceEntryFingerprintAuthInteractor: DeviceEntryFingerprintAuthInteractor,
     private val sfpsSensorInteractor: SideFpsSensorInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index ec6a17b..21c45c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -51,6 +51,7 @@
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
@@ -78,6 +79,7 @@
 import androidx.compose.ui.semantics.customActions
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.round
 import androidx.compose.ui.util.fastRoundToInt
 import androidx.compose.ui.viewinterop.AndroidView
@@ -102,6 +104,8 @@
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyboard.shortcut.ui.composable.InteractionsConfig
+import com.android.systemui.keyboard.shortcut.ui.composable.ProvideShortcutHelperIndication
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.lifecycle.setSnapshotBinding
 import com.android.systemui.media.controls.ui.view.MediaHost
@@ -240,51 +244,54 @@
 
     @Composable
     private fun Content() {
-        PlatformTheme {
-            AnimatedVisibility(
-                visible = viewModel.isQsVisible,
-                modifier =
-                    Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
-                        // Clipping before translation to match QSContainerImpl.onDraw
-                        .offset {
-                            IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt())
-                        }
-                        .thenIf(notificationScrimClippingParams.isEnabled) {
-                            Modifier.notificationScrimClip {
-                                notificationScrimClippingParams.params
+        PlatformTheme(isDarkTheme = true) {
+            ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
+                AnimatedVisibility(
+                    visible = viewModel.isQsVisible,
+                    modifier =
+                        Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
+                            // Clipping before translation to match QSContainerImpl.onDraw
+                            .offset {
+                                IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt())
                             }
+                            .thenIf(notificationScrimClippingParams.isEnabled) {
+                                Modifier.notificationScrimClip {
+                                    notificationScrimClippingParams.params
+                                }
+                            }
+                            // Disable touches in the whole composable while the mirror is showing.
+                            // While the mirror is showing, an ancestor of the ComposeView is made
+                            // alpha 0, but touches are still being captured by the composables.
+                            .gesturesDisabled(viewModel.showingMirror),
+                ) {
+                    val isEditing by
+                        viewModel.containerViewModel.editModeViewModel.isEditing
+                            .collectAsStateWithLifecycle()
+                    val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
+                    AnimatedContent(
+                        targetState = isEditing,
+                        transitionSpec = {
+                            fadeIn(animationSpecEditMode) togetherWith
+                                fadeOut(animationSpecEditMode)
+                        },
+                        label = "EditModeAnimatedContent",
+                    ) { editing ->
+                        if (editing) {
+                            val qqsPadding = viewModel.qqsHeaderHeight
+                            EditMode(
+                                viewModel = viewModel.containerViewModel.editModeViewModel,
+                                modifier =
+                                    Modifier.fillMaxWidth()
+                                        .padding(top = { qqsPadding })
+                                        .padding(
+                                            horizontal = {
+                                                QuickSettingsShade.Dimensions.Padding.roundToPx()
+                                            }
+                                        ),
+                            )
+                        } else {
+                            CollapsableQuickSettingsSTL()
                         }
-                        // Disable touches in the whole composable while the mirror is showing.
-                        // While the mirror is showing, an ancestor of the ComposeView is made
-                        // alpha 0, but touches are still being captured by the composables.
-                        .gesturesDisabled(viewModel.showingMirror),
-            ) {
-                val isEditing by
-                    viewModel.containerViewModel.editModeViewModel.isEditing
-                        .collectAsStateWithLifecycle()
-                val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS)
-                AnimatedContent(
-                    targetState = isEditing,
-                    transitionSpec = {
-                        fadeIn(animationSpecEditMode) togetherWith fadeOut(animationSpecEditMode)
-                    },
-                    label = "EditModeAnimatedContent",
-                ) { editing ->
-                    if (editing) {
-                        val qqsPadding = viewModel.qqsHeaderHeight
-                        EditMode(
-                            viewModel = viewModel.containerViewModel.editModeViewModel,
-                            modifier =
-                                Modifier.fillMaxWidth()
-                                    .padding(top = { qqsPadding })
-                                    .padding(
-                                        horizontal = {
-                                            QuickSettingsShade.Dimensions.Padding.roundToPx()
-                                        }
-                                    ),
-                        )
-                    } else {
-                        CollapsableQuickSettingsSTL()
                     }
                 }
             }
@@ -1090,3 +1097,14 @@
     const val qsScroll = "expanded_qs_scroll_view"
     const val qsFooterActions = "qs_footer_actions"
 }
+
+@Composable
+private fun interactionsConfig() =
+    InteractionsConfig(
+        hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
+        hoverOverlayAlpha = 0.11f,
+        pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
+        pressedOverlayAlpha = 0.15f,
+        // we are OK using this as our content is clipped and all corner radius are larger than this
+        surfaceCornerRadius = 28.dp,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
index 9029563..e3de6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
 import com.android.systemui.util.LargeScreenUtils
 import com.android.systemui.util.asIndenting
 import com.android.systemui.util.kotlin.emitOnStart
@@ -93,7 +94,7 @@
     private val footerActionsController: FooterActionsController,
     private val sysuiStatusBarStateController: SysuiStatusBarStateController,
     deviceEntryInteractor: DeviceEntryInteractor,
-    disableFlagsRepository: DisableFlagsRepository,
+    DisableFlagsInteractor: DisableFlagsInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val largeScreenShadeInterpolator: LargeScreenShadeInterpolator,
     @ShadeDisplayAware configurationInteractor: ConfigurationInteractor,
@@ -182,8 +183,8 @@
     val isQsEnabled by
         hydrator.hydratedStateOf(
             traceName = "isQsEnabled",
-            initialValue = disableFlagsRepository.disableFlags.value.isQuickSettingsEnabled(),
-            source = disableFlagsRepository.disableFlags.map { it.isQuickSettingsEnabled() },
+            initialValue = DisableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled(),
+            source = DisableFlagsInteractor.disableFlags.map { it.isQuickSettingsEnabled() },
         )
 
     var isInSplitShade by mutableStateOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index 2efe500..4e094cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -18,10 +18,13 @@
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Edit
 import androidx.compose.material3.Icon
@@ -32,7 +35,6 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Alignment
@@ -41,6 +43,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.padding
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.lifecycle.rememberViewModel
 import com.android.systemui.qs.panels.dagger.PaginatedBaseLayoutType
@@ -48,6 +51,7 @@
 import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout.Dimensions.InterPageSpacing
 import com.android.systemui.qs.panels.ui.viewmodel.PaginatedGridViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+import com.android.systemui.qs.ui.compose.borderOnFocus
 import com.android.systemui.res.R
 import javax.inject.Inject
 
@@ -89,9 +93,24 @@
         }
 
         Column {
+            val contentPaddingValue =
+                if (pages.size > 1) {
+                    InterPageSpacing
+                } else {
+                    0.dp
+                }
+            val contentPadding = PaddingValues(horizontal = contentPaddingValue)
+
+            /* Use negative padding equal with value equal to content padding. That way, each page
+             * layout extends to the sides, but the content is as if there was no padding. That
+             * way, the clipping bounds of the HorizontalPager extend beyond the tiles in each page.
+             */
             HorizontalPager(
                 state = pagerState,
-                modifier = Modifier.sysuiResTag("qs_pager"),
+                modifier =
+                    Modifier.sysuiResTag("qs_pager")
+                        .padding(horizontal = { -contentPaddingValue.roundToPx() }),
+                contentPadding = contentPadding,
                 pageSpacing = if (pages.size > 1) InterPageSpacing else 0.dp,
                 beyondViewportPageCount = 1,
                 verticalAlignment = Alignment.Top,
@@ -114,7 +133,13 @@
                 CompositionLocalProvider(value = LocalContentColor provides Color.White) {
                     IconButton(
                         onClick = editModeStart,
-                        modifier = Modifier.align(Alignment.CenterEnd),
+                        shape = RoundedCornerShape(CornerSize(28.dp)),
+                        modifier =
+                            Modifier.align(Alignment.CenterEnd)
+                                .borderOnFocus(
+                                    color = MaterialTheme.colorScheme.secondary,
+                                    cornerSize = CornerSize(FooterHeight / 2),
+                                ),
                     ) {
                         Icon(
                             imageVector = Icons.Default.Edit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index 177a5be..dbad602 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.panels.ui.compose.infinitegrid
 
 import android.graphics.drawable.Animatable
+import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.Drawable
 import android.text.TextUtils
 import androidx.compose.animation.animateColorAsState
@@ -50,7 +51,6 @@
 import androidx.compose.ui.draw.drawBehind
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.Role
@@ -75,6 +75,7 @@
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconWidth
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
+import com.android.systemui.qs.ui.compose.borderOnFocus
 import com.android.systemui.res.R
 
 private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
@@ -88,7 +89,7 @@
     colors: TileColors,
     squishiness: () -> Float,
     accessibilityUiState: AccessibilityUiState? = null,
-    iconShape: Shape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius),
+    iconShape: RoundedCornerShape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius),
     toggleClick: (() -> Unit)? = null,
     onLongClick: (() -> Unit)? = null,
 ) {
@@ -100,10 +101,12 @@
         val longPressLabel = longPressLabel().takeIf { onLongClick != null }
         val animatedBackgroundColor by
             animateColorAsState(colors.iconBackground, label = "QSTileDualTargetBackgroundColor")
+        val focusBorderColor = MaterialTheme.colorScheme.secondary
         Box(
             modifier =
                 Modifier.size(CommonTileDefaults.ToggleTargetSize).thenIf(toggleClick != null) {
-                    Modifier.clip(iconShape)
+                    Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd)
+                        .clip(iconShape)
                         .verticalSquish(squishiness)
                         .drawBehind { drawRect(animatedBackgroundColor) }
                         .combinedClickable(
@@ -226,7 +229,14 @@
                         }
                     }
                 }
-                is Icon.Loaded -> rememberDrawablePainter(loadedDrawable)
+                is Icon.Loaded -> {
+                    LaunchedEffect(loadedDrawable) {
+                        if (loadedDrawable is AnimatedVectorDrawable) {
+                            loadedDrawable.forceAnimationOnUI()
+                        }
+                    }
+                    rememberDrawablePainter(loadedDrawable)
+                }
             }
 
         Image(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index fe59c4d3..cb57c67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -39,6 +39,7 @@
 import androidx.compose.foundation.lazy.grid.LazyGridState
 import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
 import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
@@ -49,6 +50,7 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.platform.LocalConfiguration
@@ -59,6 +61,7 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -82,6 +85,7 @@
 import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.toUiState
 import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.ui.compose.borderOnFocus
 import com.android.systemui.res.R
 import java.util.function.Supplier
 import kotlinx.coroutines.CoroutineScope
@@ -139,6 +143,7 @@
         hapticsViewModel = hapticsViewModel,
         modifier =
             modifier
+                .borderOnFocus(color = MaterialTheme.colorScheme.secondary, tileShape.topEnd)
                 .fillMaxWidth()
                 .bounceable(
                     bounceable = currentBounceableInfo.bounceable,
@@ -381,7 +386,7 @@
     }
 
     @Composable
-    fun animateIconShape(state: Int): Shape {
+    fun animateIconShape(state: Int): RoundedCornerShape {
         return animateShape(
             state = state,
             activeCornerRadius = ActiveIconCornerRadius,
@@ -390,7 +395,7 @@
     }
 
     @Composable
-    fun animateTileShape(state: Int): Shape {
+    fun animateTileShape(state: Int): RoundedCornerShape {
         return animateShape(
             state = state,
             activeCornerRadius = ActiveTileCornerRadius,
@@ -399,7 +404,7 @@
     }
 
     @Composable
-    fun animateShape(state: Int, activeCornerRadius: Dp, label: String): Shape {
+    fun animateShape(state: Int, activeCornerRadius: Dp, label: String): RoundedCornerShape {
         val animatedCornerRadius by
             animateDpAsState(
                 targetValue =
@@ -410,7 +415,15 @@
                     },
                 label = label,
             )
-        return RoundedCornerShape(animatedCornerRadius)
+
+        val corner = remember {
+            object : CornerSize {
+                override fun toPx(shapeSize: Size, density: Density): Float {
+                    return with(density) { animatedCornerRadius.toPx() }
+                }
+            }
+        }
+        return RoundedCornerShape(corner)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 301ab2b..8f6c4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -1429,7 +1429,7 @@
     void makeOverlayToast(int stringId) {
         final Resources res = mContext.getResources();
 
-        final SystemUIToast systemUIToast = mToastFactory.createToast(mContext,
+        final SystemUIToast systemUIToast = mToastFactory.createToast(mContext, mContext,
                 res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(),
                 res.getConfiguration().orientation);
         if (systemUIToast == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
index 736e1a5..57a60c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt
@@ -75,10 +75,10 @@
     override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
 
     private fun hasSufficientPermission(): Boolean {
-        val rotationPackage: String = packageManager.rotationResolverPackageName
-        return rotationPackage != null &&
-            packageManager.checkPermission(Manifest.permission.CAMERA, rotationPackage) ==
+        return packageManager.rotationResolverPackageName?.let {
+            packageManager.checkPermission(Manifest.permission.CAMERA, it) ==
                 PackageManager.PERMISSION_GRANTED
+        } ?: false
     }
 
     private fun isCameraRotationEnabled(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt
new file mode 100644
index 0000000..e6caa0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/compose/BorderOnFocus.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.compose
+
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusEventModifierNode
+import androidx.compose.ui.focus.FocusState
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.node.DrawModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Provides a rounded rect border when the element is focused.
+ *
+ * This should be used for elements that are themselves rounded rects.
+ */
+fun Modifier.borderOnFocus(
+    color: Color,
+    cornerSize: CornerSize,
+    strokeWidth: Dp = 3.dp,
+    padding: Dp = 2.dp,
+) = this then BorderOnFocusElement(color, cornerSize, strokeWidth, padding)
+
+private class BorderOnFocusNode(
+    var color: Color,
+    var cornerSize: CornerSize,
+    var strokeWidth: Dp,
+    var padding: Dp,
+) : FocusEventModifierNode, DrawModifierNode, Modifier.Node() {
+
+    private var focused by mutableStateOf(false)
+
+    override fun onFocusEvent(focusState: FocusState) {
+        focused = focusState.isFocused
+    }
+
+    override fun ContentDrawScope.draw() {
+        drawContent()
+        val focusOutline = Rect(Offset.Zero, size).inflate(padding.toPx())
+        if (focused) {
+            drawRoundRect(
+                color = color,
+                topLeft = focusOutline.topLeft,
+                size = focusOutline.size,
+                cornerRadius = CornerRadius(cornerSize.toPx(focusOutline.size, this)),
+                style = Stroke(strokeWidth.toPx()),
+            )
+        }
+    }
+}
+
+private data class BorderOnFocusElement(
+    val color: Color,
+    val cornerSize: CornerSize,
+    val strokeWidth: Dp,
+    val padding: Dp,
+) : ModifierNodeElement<BorderOnFocusNode>() {
+    override fun create(): BorderOnFocusNode {
+        return BorderOnFocusNode(color, cornerSize, strokeWidth, padding)
+    }
+
+    override fun update(node: BorderOnFocusNode) {
+        node.color = color
+        node.cornerSize = cornerSize
+        node.strokeWidth = strokeWidth
+        node.padding = padding
+    }
+
+    override fun InspectorInfo.inspectableProperties() {
+        name = "borderOnFocus"
+        properties["color"] = color
+        properties["cornerSize"] = cornerSize
+        properties["strokeWidth"] = strokeWidth
+        properties["padding"] = padding
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index 667827a..c96ea03 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -138,6 +138,7 @@
                 Overlays.QuickSettingsShade -> false
                 Scenes.Bouncer -> false
                 Scenes.Communal -> true
+                Scenes.Dream -> false
                 Scenes.Gone -> true
                 Scenes.Lockscreen -> true
                 Scenes.QuickSettings -> false
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
index 41a3c8a..b89eb5c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.scene.shared.model.SceneFamilies
 import com.android.systemui.scene.shared.model.Scenes
 import dagger.Binds
@@ -46,6 +47,7 @@
 constructor(
     @Application private val applicationScope: CoroutineScope,
     deviceEntryInteractor: DeviceEntryInteractor,
+    keyguardInteractor: KeyguardInteractor,
     keyguardEnabledInteractor: KeyguardEnabledInteractor,
 ) : SceneResolver {
     override val targetFamily: SceneKey = SceneFamilies.Home
@@ -56,6 +58,7 @@
                 deviceEntryInteractor.canSwipeToEnter,
                 deviceEntryInteractor.isDeviceEntered,
                 deviceEntryInteractor.isUnlocked,
+                keyguardInteractor.isDreamingWithOverlay,
                 transform = ::homeScene,
             )
             .stateIn(
@@ -67,7 +70,8 @@
                         canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value,
                         isDeviceEntered = deviceEntryInteractor.isDeviceEntered.value,
                         isUnlocked = deviceEntryInteractor.isUnlocked.value,
-                    )
+                        isDreamingWithOverlay = false,
+                    ),
             )
 
     override fun includesScene(scene: SceneKey): Boolean = scene in homeScenes
@@ -77,8 +81,11 @@
         canSwipeToEnter: Boolean?,
         isDeviceEntered: Boolean,
         isUnlocked: Boolean,
+        isDreamingWithOverlay: Boolean,
     ): SceneKey =
         when {
+            // Dream can run even if Keyguard is disabled, thus it has the highest priority here.
+            isDreamingWithOverlay -> Scenes.Dream
             !isKeyguardEnabled -> Scenes.Gone
             canSwipeToEnter == true -> Scenes.Lockscreen
             !isDeviceEntered -> Scenes.Lockscreen
@@ -91,6 +98,9 @@
             setOf(
                 Scenes.Gone,
                 Scenes.Lockscreen,
+                // Dream is a home scene as the dream activity occludes keyguard and can show the
+                // shade on top.
+                Scenes.Dream,
             )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index daeaaa5..9125d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.logger.SceneLogger
 import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.SceneFamilies
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -217,7 +218,9 @@
                                 sceneInteractor.transitionState.mapNotNull { state ->
                                     when (state) {
                                         is ObservableTransitionState.Idle -> {
-                                            if (state.currentScene != Scenes.Gone) {
+                                            if (state.currentScene == Scenes.Dream) {
+                                                false to "dream is showing"
+                                            } else if (state.currentScene != Scenes.Gone) {
                                                 true to "scene is not Gone"
                                             } else if (state.currentOverlays.isNotEmpty()) {
                                                 true to "overlay is shown"
@@ -228,21 +231,30 @@
                                         is ObservableTransitionState.Transition -> {
                                             if (state.fromContent == Scenes.Gone) {
                                                 true to "scene transitioning away from Gone"
+                                            } else if (state.fromContent == Scenes.Dream) {
+                                                true to "scene transitioning away from dream"
                                             } else {
                                                 null
                                             }
                                         }
                                     }
                                 },
+                                sceneInteractor.transitionState.map { state ->
+                                    state.isTransitioningFromOrTo(Scenes.Communal) ||
+                                        state.isIdle(Scenes.Communal)
+                                },
                                 headsUpInteractor.isHeadsUpOrAnimatingAway,
                                 occlusionInteractor.invisibleDueToOcclusion,
                                 alternateBouncerInteractor.isVisible,
                             ) {
                                 visibilityForTransitionState,
+                                isCommunalShowing,
                                 isHeadsUpOrAnimatingAway,
                                 invisibleDueToOcclusion,
                                 isAlternateBouncerVisible ->
                                 when {
+                                    isCommunalShowing ->
+                                        true to "on or transitioning to/from communal"
                                     isHeadsUpOrAnimatingAway -> true to "showing a HUN"
                                     isAlternateBouncerVisible -> true to "showing alternate bouncer"
                                     invisibleDueToOcclusion -> false to "invisible due to occlusion"
@@ -266,6 +278,7 @@
         handleSimUnlock()
         handleDeviceUnlockStatus()
         handlePowerState()
+        handleDreamState()
         handleShadeTouchability()
     }
 
@@ -506,6 +519,31 @@
         }
     }
 
+    private fun handleDreamState() {
+        applicationScope.launch {
+            keyguardInteractor.isAbleToDream
+                .sample(sceneInteractor.transitionState, ::Pair)
+                .collect { (isAbleToDream, transitionState) ->
+                    if (transitionState.isIdle(Scenes.Communal)) {
+                        // The dream is automatically started underneath the hub, don't transition
+                        // to dream when this is happening as communal is still visible on top.
+                        return@collect
+                    }
+                    if (isAbleToDream) {
+                        switchToScene(
+                            targetSceneKey = Scenes.Dream,
+                            loggingReason = "dream started",
+                        )
+                    } else {
+                        switchToScene(
+                            targetSceneKey = SceneFamilies.Home,
+                            loggingReason = "dream stopped",
+                        )
+                    }
+                }
+        }
+    }
+
     private fun handleShadeTouchability() {
         applicationScope.launch {
             shadeInteractor.isShadeTouchable
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 3a90d2b..503d0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -235,8 +235,7 @@
         if (mBrightnessWarningToast.isToastActive()) {
             return;
         }
-        mBrightnessWarningToast.show(mView.getContext(),
-                R.string.quick_settings_brightness_unable_adjust_msg);
+        mBrightnessWarningToast.show(mView.getContext(), resId);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
index dfbdaa6..40260d0 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt
@@ -37,11 +37,14 @@
     private var toastView: View? = null
 
     fun show(viewContext: Context, @StringRes resId: Int) {
+        if (isToastActive()) {
+            return
+        }
         val res = viewContext.resources
         // Show the brightness warning toast with passing the toast inflation required context,
         // userId and resId from SystemUI package.
         val systemUIToast = toastFactory.createToast(
-            viewContext,
+            viewContext, viewContext,
             res.getString(resId), viewContext.packageName, viewContext.getUserId(),
             res.configuration.orientation
         )
@@ -79,13 +82,15 @@
         val inAnimator = systemUIToast.inAnimation
         inAnimator?.start()
 
-        toastView!!.postDelayed({
+        toastView?.postDelayed({
             val outAnimator = systemUIToast.outAnimation
             if (outAnimator != null) {
                 outAnimator.start()
                 outAnimator.addListener(object : AnimatorListenerAdapter() {
                     override fun onAnimationEnd(animator: Animator) {
-                        windowManager.removeViewImmediate(toastView)
+                        if (isToastActive()) {
+                            windowManager.removeViewImmediate(toastView)
+                        }
                         toastView = null
                     }
                 })
@@ -94,7 +99,7 @@
     }
 
     fun isToastActive(): Boolean {
-        return toastView != null && toastView!!.isAttachedToWindow
+        return toastView?.isAttachedToWindow == true
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index c15c8f9..4ccd2b9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2053,9 +2053,6 @@
         }
         if (mQsController.getExpanded()) {
             mQsController.flingQs(0, FLING_COLLAPSE);
-        } else if (mBarState == KEYGUARD) {
-            mLockscreenShadeTransitionController.goToLockedShade(
-                    /* expandedView= */null, /* needsQSAnimation= */false);
         } else {
             expand(true /* animate */);
         }
@@ -3116,8 +3113,14 @@
             mShadeLog.d("Status Bar was long pressed. Expanding to QS.");
             expandToQs();
         } else {
-            mShadeLog.d("Status Bar was long pressed. Expanding to Notifications.");
-            expandToNotifications();
+            if (mBarState == KEYGUARD) {
+                mShadeLog.d("Lockscreen Status Bar was long pressed. Expanding to Notifications.");
+                mLockscreenShadeTransitionController.goToLockedShade(
+                        /* expandedView= */null, /* needsQSAnimation= */false);
+            } else {
+                mShadeLog.d("Status Bar was long pressed. Expanding to Notifications.");
+                expandToNotifications();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 24dba59..4d77e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -17,8 +17,6 @@
 package com.android.systemui.shade;
 
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
 
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -27,16 +25,13 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
-import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.os.Binder;
 import android.os.Build;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.util.Log;
 import android.view.Display;
-import android.view.Gravity;
 import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.View;
@@ -271,33 +266,7 @@
         // Now that the notification shade encompasses the sliding panel and its
         // translucent backdrop, the entire thing is made TRANSLUCENT and is
         // hardware-accelerated.
-        mLp = new LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                LayoutParams.TYPE_NOTIFICATION_SHADE,
-                LayoutParams.FLAG_NOT_FOCUSABLE
-                        | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                        | LayoutParams.FLAG_SPLIT_TOUCH
-                        | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                PixelFormat.TRANSLUCENT);
-        mLp.token = new Binder();
-        mLp.gravity = Gravity.TOP;
-        mLp.setFitInsetsTypes(0 /* types */);
-        mLp.setTitle("NotificationShade");
-        mLp.packageName = mContext.getPackageName();
-        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        mLp.privateFlags |= PRIVATE_FLAG_OPTIMIZE_MEASURE;
-
-        if (SceneContainerFlag.isEnabled()) {
-            // This prevents the appearance and disappearance of the software keyboard (also known
-            // as the "IME") from scrolling/panning the window to make room for the keyboard.
-            //
-            // The scene container logic does its own adjustment and animation when the IME appears
-            // or disappears.
-            mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        }
-
+        mLp = ShadeWindowLayoutParams.INSTANCE.create(mContext);
         mWindowManager.addView(mWindowRootView, mLp);
 
         // We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 7a18d7c..207439e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -28,6 +28,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import androidx.lifecycle.lifecycleScope
 import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.customization.R as customR
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.fragments.FragmentService
@@ -314,7 +315,7 @@
 
     private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) {
         val statusViewMarginHorizontal =
-            resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+            resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal)
         constraintSet.apply {
             setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal)
             setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index e15830e..fed4a26 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -30,8 +30,8 @@
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.res.R
-import com.android.systemui.shade.data.repository.ShadePositionRepository
-import com.android.systemui.shade.data.repository.ShadePositionRepositoryImpl
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
 import com.android.systemui.statusbar.phone.ConfigurationForwarder
@@ -157,16 +157,16 @@
 
     @SysUISingleton
     @Provides
-    fun provideShadePositionRepository(impl: ShadePositionRepositoryImpl): ShadePositionRepository {
+    fun provideShadePositionRepository(impl: ShadeDisplaysRepositoryImpl): ShadeDisplaysRepository {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         return impl
     }
 
     @Provides
     @IntoMap
-    @ClassKey(ShadePositionRepositoryImpl::class)
+    @ClassKey(ShadeDisplaysRepositoryImpl::class)
     fun provideShadePositionRepositoryAsCoreStartable(
-        impl: ShadePositionRepositoryImpl
+        impl: ShadeDisplaysRepositoryImpl
     ): CoreStartable {
         return if (ShadeWindowGoesAround.isEnabled) {
             impl
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
index 802fc0e..506b4e9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt
@@ -17,11 +17,11 @@
 package com.android.systemui.shade
 
 import android.view.Display
-import com.android.systemui.shade.data.repository.ShadePositionRepository
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.statusbar.commandline.Command
 import java.io.PrintWriter
 
-class ShadePrimaryDisplayCommand(private val positionRepository: ShadePositionRepository) :
+class ShadePrimaryDisplayCommand(private val positionRepository: ShadeDisplaysRepository) :
     Command {
 
     override fun execute(pw: PrintWriter, args: List<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt
new file mode 100644
index 0000000..6bb50f9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.shade
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.os.Binder
+import android.view.Gravity
+import android.view.ViewGroup
+import android.view.WindowManager.LayoutParams
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+
+object ShadeWindowLayoutParams {
+    /**
+     * Creates [LayoutParams] for the shade window.
+     *
+     * This is extracted to a single place as those layout params will be used by several places:
+     * - When sysui starts, and the shade is added the first time
+     * - When the shade moves to a different window (e.g. while an external display is connected)
+     */
+    fun create(context: Context): LayoutParams {
+        return LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                LayoutParams.TYPE_NOTIFICATION_SHADE,
+                LayoutParams.FLAG_NOT_FOCUSABLE or
+                    LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING or
+                    LayoutParams.FLAG_SPLIT_TOUCH or
+                    LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
+                    LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                // Now that the notification shade encompasses the sliding panel and its
+                // translucent backdrop, the entire thing is made TRANSLUCENT and is
+                // hardware-accelerated.
+                PixelFormat.TRANSLUCENT,
+            )
+            .apply {
+                token = Binder()
+                gravity = Gravity.TOP
+                fitInsetsTypes = 0
+                title = "NotificationShade"
+                packageName = context.packageName
+                layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+                privateFlags = privateFlags or LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE
+                if (SceneContainerFlag.isEnabled) {
+                    // This prevents the appearance and disappearance of the software keyboard (also
+                    // known as the "IME") from scrolling/panning the window to make room for the
+                    // keyboard.
+                    //
+                    // The scene container logic does its own adjustment and animation when the IME
+                    // appears or disappears.
+                    softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING
+                }
+            }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt
rename to packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
index 37210b9..71c5658 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
@@ -20,7 +20,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
-class FakeShadePositionRepository : ShadePositionRepository {
+class FakeShadeDisplayRepository : ShadeDisplaysRepository {
     private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
 
     override fun setDisplayId(displayId: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt
rename to packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index 24c067a..e920aba 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -25,7 +25,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
-interface ShadePositionRepository {
+interface ShadeDisplaysRepository {
     /** ID of the display which currently hosts the shade */
     val displayId: StateFlow<Int>
 
@@ -41,9 +41,9 @@
 
 /** Source of truth for the display currently holding the shade. */
 @SysUISingleton
-class ShadePositionRepositoryImpl
+class ShadeDisplaysRepositoryImpl
 @Inject
-constructor(private val commandRegistry: CommandRegistry) : ShadePositionRepository, CoreStartable {
+constructor(private val commandRegistry: CommandRegistry) : ShadeDisplaysRepository, CoreStartable {
     private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
 
     override val displayId: StateFlow<Int>
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
new file mode 100644
index 0000000..1055dcb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.domain.interactor
+
+import android.content.Context
+import android.util.Log
+import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE
+import com.android.app.tracing.coroutines.launchTraced
+import com.android.app.tracing.traceSection
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.shared.model.DisplayWindowProperties
+import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.ShadeDisplayAware
+import com.android.systemui.shade.ShadeWindowLayoutParams
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import com.android.systemui.statusbar.phone.ConfigurationForwarder
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.withContext
+
+/** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */
+@SysUISingleton
+class ShadeDisplaysInteractor
+@Inject
+constructor(
+    private val shadeRootView: WindowRootView,
+    private val shadePositionRepository: ShadeDisplaysRepository,
+    @ShadeDisplayAware private val shadeContext: Context,
+    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    @Background private val bgScope: CoroutineScope,
+    @ShadeDisplayAware private val configurationForwarder: ConfigurationForwarder,
+    @Main private val mainContext: CoroutineContext,
+) : CoreStartable {
+
+    override fun start() {
+        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+        bgScope.launchTraced(TAG) {
+            shadePositionRepository.displayId.collect { displayId -> moveShadeWindowTo(displayId) }
+        }
+    }
+
+    /** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */
+    private suspend fun moveShadeWindowTo(destinationDisplayId: Int) {
+        val currentId = shadeRootView.display.displayId
+        if (currentId == destinationDisplayId) {
+            Log.w(TAG, "Trying to move the shade to a display it was already in")
+            return
+        }
+        try {
+            moveShadeWindow(fromId = currentId, toId = destinationDisplayId)
+        } catch (e: IllegalStateException) {
+            Log.e(
+                TAG,
+                "Unable to move the shade window from display $currentId to $destinationDisplayId",
+                e,
+            )
+        }
+    }
+
+    private suspend fun moveShadeWindow(fromId: Int, toId: Int) {
+        val sourceProperties = getDisplayWindowProperties(fromId)
+        val destinationProperties = getDisplayWindowProperties(toId)
+        traceSection({ "MovingShadeWindow from $fromId to $toId" }) {
+            withContext(mainContext) {
+                traceSection("removeView") {
+                    sourceProperties.windowManager.removeView(shadeRootView)
+                }
+                traceSection("addView") {
+                    destinationProperties.windowManager.addView(
+                        shadeRootView,
+                        ShadeWindowLayoutParams.create(shadeContext),
+                    )
+                }
+            }
+        }
+        traceSection("SecondaryShadeInteractor#onConfigurationChanged") {
+            configurationForwarder.onConfigurationChanged(
+                destinationProperties.context.resources.configuration
+            )
+        }
+    }
+
+    private fun getDisplayWindowProperties(displayId: Int): DisplayWindowProperties {
+        return displayWindowPropertiesRepository.get(displayId, TYPE_NOTIFICATION_SHADE)
+    }
+
+    private companion object {
+        const val TAG = "SecondaryShadeInteractor"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 460bfbb..a653ca2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.keyguard.shared.model.Edge
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
 import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
@@ -47,7 +47,7 @@
 constructor(
     @Application val scope: CoroutineScope,
     deviceProvisioningInteractor: DeviceProvisioningInteractor,
-    disableFlagsRepository: DisableFlagsRepository,
+    disableFlagsInteractor: DisableFlagsInteractor,
     dozeParams: DozeParameters,
     keyguardRepository: KeyguardRepository,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
@@ -61,13 +61,13 @@
     BaseShadeInteractor by baseShadeInteractor,
     ShadeModeInteractor by shadeModeInteractor {
     override val isShadeEnabled: StateFlow<Boolean> =
-        disableFlagsRepository.disableFlags
+        disableFlagsInteractor.disableFlags
             .map { it.isShadeEnabled() }
             .flowName("isShadeEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isQsEnabled: StateFlow<Boolean> =
-        disableFlagsRepository.disableFlags
+        disableFlagsInteractor.disableFlags
             .map { it.isQuickSettingsEnabled() }
             .flowName("isQsEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
@@ -114,7 +114,7 @@
 
     override val isExpandToQsEnabled: Flow<Boolean> =
         combine(
-            disableFlagsRepository.disableFlags,
+            disableFlagsInteractor.disableFlags,
             isShadeEnabled,
             keyguardRepository.isDozing,
             userSetupRepository.isUserSetUp,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 33f0c64..6bec86a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -177,8 +177,6 @@
     private float[] mMatrix;
     private ColorMatrixColorFilter mMatrixColorFilter;
     private Runnable mLayoutRunnable;
-    private boolean mDismissed;
-    private Runnable mOnDismissListener;
     private boolean mIncreasedSize;
     private boolean mShowsConversation;
     private float mDozeAmount;
@@ -956,21 +954,6 @@
         mLayoutRunnable = runnable;
     }
 
-    public void setDismissed() {
-        mDismissed = true;
-        if (mOnDismissListener != null) {
-            mOnDismissListener.run();
-        }
-    }
-
-    public boolean isDismissed() {
-        return mDismissed;
-    }
-
-    public void setOnDismissListener(Runnable onDismissListener) {
-        mOnDismissListener = onDismissListener;
-    }
-
     @Override
     public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
         int areaTint = getTint(areas, this, tint);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index da04f6e..b2ca33a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -705,6 +705,7 @@
         final boolean onBouncer = currentScene.equals(Scenes.Bouncer);
         final boolean onCommunal = currentScene.equals(Scenes.Communal);
         final boolean onGone = currentScene.equals(Scenes.Gone);
+        final boolean onDream = currentScene.equals(Scenes.Dream);
         final boolean onLockscreen = currentScene.equals(Scenes.Lockscreen);
         final boolean onQuickSettings = currentScene.equals(Scenes.QuickSettings);
         final boolean onShade = currentScene.equals(Scenes.Shade);
@@ -765,6 +766,8 @@
             // We get here if deviceUnlockStatus.isUnlocked is false but we are no longer on or over
             // a keyguardish scene; we want to return SHADE_LOCKED until isUnlocked is also true.
             newState = StatusBarState.SHADE_LOCKED;
+        } else if (onDream) {
+            newState = StatusBarState.SHADE_LOCKED;
         } else {
             throw new IllegalArgumentException(
                     "unhandled input to calculateStateFromSceneFramework: " + inputLogString);
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt
similarity index 67%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt
index e4ccc2c..6c1d6c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/StatusBarChipLogTags.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package com.android.systemui.statusbar.chips
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+/** Helper class to ensure all tags used in [StatusBarChipsLog] are exactly the same length. */
+object StatusBarChipLogTags {
+    private const val TAG_LENGTH = 20
+
+    fun String.pad(): String {
+        return this.padEnd(TAG_LENGTH)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
index eaefc11..bb0467f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
@@ -47,6 +48,6 @@
             .stateIn(scope, SharingStarted.Lazily, OngoingCallModel.NoCall)
 
     companion object {
-        private const val TAG = "OngoingCall"
+        private val TAG = "OngoingCall".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index e825258..b8cdd25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
 import com.android.systemui.statusbar.chips.ui.model.ColorsModel
@@ -112,7 +113,7 @@
                 ActivityTransitionAnimator.Controller.fromView(
                     backgroundView,
                     InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
-                )
+                ),
             )
         }
     }
@@ -121,10 +122,8 @@
         private val phoneIcon =
             Icon.Resource(
                 com.android.internal.R.drawable.ic_phone,
-                ContentDescription.Resource(
-                    R.string.ongoing_phone_call_content_description,
-                ),
+                ContentDescription.Resource(R.string.ongoing_phone_call_content_description),
             )
-        private const val TAG = "CallVM"
+        private val TAG = "CallVM".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
index 7c95f1e..b3dbf29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.mediarouter.data.repository.MediaRouterRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.casttootherdevice.domain.model.MediaRouterCastModel
 import com.android.systemui.statusbar.policy.CastDevice
@@ -68,6 +69,6 @@
     }
 
     companion object {
-        private const val TAG = "MediaRouter"
+        private val TAG = "MediaRouter".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
index 1107206..3422337 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModel.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.casttootherdevice.domain.interactor.MediaRouterChipInteractor
 import com.android.systemui.statusbar.chips.casttootherdevice.domain.model.MediaRouterCastModel
@@ -255,6 +256,6 @@
 
     companion object {
         @DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected
-        private const val TAG = "CastToOtherVM"
+        private val TAG = "CastToOtherVM".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index 27b2465..af238f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
 
 import android.content.pm.PackageManager
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -25,6 +26,7 @@
 import com.android.systemui.mediaprojection.MediaProjectionUtils.packageHasCastingCapabilities
 import com.android.systemui.mediaprojection.data.model.MediaProjectionState
 import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
 import javax.inject.Inject
@@ -33,7 +35,6 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /**
  * Interactor for media projection events, used to show chips in the status bar for share-to-app and
@@ -108,6 +109,6 @@
     }
 
     companion object {
-        private const val TAG = "MediaProjection"
+        private val TAG = "MediaProjection".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index e3dc70a..f5952f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel
 import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.screenrecord.domain.model.ScreenRecordChipModel
 import javax.inject.Inject
@@ -143,6 +144,6 @@
     }
 
     companion object {
-        private const val TAG = "ScreenRecord"
+        private val TAG = "ScreenRecord".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
index eb73521..0065593 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModel.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.res.R
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel.Starting.Companion.toCountdownSeconds
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndMediaProjectionDialogHelper
 import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
@@ -84,7 +85,7 @@
                                     Icon.Resource(
                                         ICON,
                                         ContentDescription.Resource(
-                                            R.string.screenrecord_ongoing_screen_only,
+                                            R.string.screenrecord_ongoing_screen_only
                                         ),
                                     )
                                 ),
@@ -153,6 +154,6 @@
 
     companion object {
         @DrawableRes val ICON = R.drawable.ic_screenrecord
-        private const val TAG = "ScreenRecordVM"
+        private val TAG = "ScreenRecordVM".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
index 11d077f..2af86a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModel.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
 import com.android.systemui.statusbar.chips.mediaprojection.domain.model.ProjectionChipModel
@@ -179,6 +180,6 @@
 
     companion object {
         @DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_present_to_all
-        private const val TAG = "ShareToAppVM"
+        private val TAG = "ShareToAppVM".pad()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index ed32597..45efc57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.chips.call.ui.viewmodel.CallChipViewModel
 import com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel.CastToOtherDeviceChipViewModel
@@ -347,7 +348,7 @@
     }
 
     companion object {
-        private const val TAG = "ChipsViewModel"
+        private val TAG = "ChipsViewModel".pad()
 
         private val DEFAULT_INTERNAL_HIDDEN_MODEL =
             InternalChipModel.Hidden(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
index 9004e5d..aeeb042 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt
@@ -22,7 +22,7 @@
 import com.android.systemui.log.dagger.DisableFlagsRepositoryLog
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt
new file mode 100644
index 0000000..4f1b978
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+@SysUISingleton
+class DisableFlagsInteractor @Inject constructor(repository: DisableFlagsRepository) {
+    /** A model of the disable flags last received from [IStatusBar]. */
+    val disableFlags: StateFlow<DisableFlagsModel> = repository.disableFlags
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt
index ce25cf5..6507237 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt
@@ -1,18 +1,20 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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
+ * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-package com.android.systemui.statusbar.disableflags.data.model
+package com.android.systemui.statusbar.disableflags.shared.model
 
 import android.app.StatusBarManager.DISABLE2_NONE
 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
deleted file mode 100644
index 0299ebc..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
+++ /dev/null
@@ -1,772 +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.statusbar.notification;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Region;
-import android.os.Handler;
-import android.util.ArrayMap;
-import android.util.Pools;
-
-import androidx.collection.ArraySet;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.SystemBarUtils;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.res.R;
-import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
-import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
-import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
-import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.AnimationStateHandler;
-import com.android.systemui.statusbar.policy.AvalancheController;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManager;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.kotlin.JavaAdapter;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.time.SystemClock;
-
-import kotlinx.coroutines.flow.Flow;
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-import kotlinx.coroutines.flow.StateFlowKt;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.Stack;
-
-import javax.inject.Inject;
-
-/** A implementation of HeadsUpManager for phone. */
-@SysUISingleton
-public class HeadsUpManagerPhone extends BaseHeadsUpManager implements
-        HeadsUpRepository, OnHeadsUpChangedListener {
-    private static final String TAG = "HeadsUpManagerPhone";
-
-    @VisibleForTesting
-    public final int mExtensionTime;
-    private final KeyguardBypassController mBypassController;
-    private final GroupMembershipManager mGroupMembershipManager;
-    private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
-    private final VisualStabilityProvider mVisualStabilityProvider;
-
-    private AvalancheController mAvalancheController;
-
-    // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
-    private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
-            StateFlowKt.MutableStateFlow(null);
-    private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =
-            StateFlowKt.MutableStateFlow(new HashSet<>());
-    private final MutableStateFlow<Boolean> mHeadsUpAnimatingAway =
-            StateFlowKt.MutableStateFlow(false);
-    private boolean mReleaseOnExpandFinish;
-    private boolean mTrackingHeadsUp;
-    private final HashSet<String> mSwipedOutKeys = new HashSet<>();
-    private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
-    @VisibleForTesting
-    public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
-            = new ArraySet<>();
-    private boolean mIsShadeOrQsExpanded;
-    private boolean mIsQsExpanded;
-    private int mStatusBarState;
-    private AnimationStateHandler mAnimationStateHandler;
-
-    private int mHeadsUpInset;
-
-    // Used for determining the region for touch interaction
-    private final Region mTouchableRegion = new Region();
-
-    private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
-        private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
-
-        @Override
-        public HeadsUpEntryPhone acquire() {
-            NotificationThrottleHun.assertInLegacyMode();
-            if (!mPoolObjects.isEmpty()) {
-                return mPoolObjects.pop();
-            }
-            return new HeadsUpEntryPhone();
-        }
-
-        @Override
-        public boolean release(@NonNull HeadsUpEntryPhone instance) {
-            NotificationThrottleHun.assertInLegacyMode();
-            mPoolObjects.push(instance);
-            return true;
-        }
-    };
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  Constructor:
-    @Inject
-    public HeadsUpManagerPhone(
-            @NonNull final Context context,
-            HeadsUpManagerLogger logger,
-            StatusBarStateController statusBarStateController,
-            KeyguardBypassController bypassController,
-            GroupMembershipManager groupMembershipManager,
-            VisualStabilityProvider visualStabilityProvider,
-            ConfigurationController configurationController,
-            @Main Handler handler,
-            GlobalSettings globalSettings,
-            SystemClock systemClock,
-            @Main DelayableExecutor executor,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            UiEventLogger uiEventLogger,
-            JavaAdapter javaAdapter,
-            ShadeInteractor shadeInteractor,
-            AvalancheController avalancheController) {
-        super(context, logger, handler, globalSettings, systemClock, executor,
-                accessibilityManagerWrapper, uiEventLogger, avalancheController);
-        Resources resources = mContext.getResources();
-        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
-        statusBarStateController.addCallback(mStatusBarStateListener);
-        mBypassController = bypassController;
-        mGroupMembershipManager = groupMembershipManager;
-        mVisualStabilityProvider = visualStabilityProvider;
-        mAvalancheController = avalancheController;
-        updateResources();
-        configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
-            @Override
-            public void onDensityOrFontScaleChanged() {
-                updateResources();
-            }
-
-            @Override
-            public void onThemeChanged() {
-                updateResources();
-            }
-        });
-        javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
-                    this::onShadeOrQsExpanded);
-        if (SceneContainerFlag.isEnabled()) {
-            javaAdapter.alwaysCollectFlow(shadeInteractor.isQsExpanded(),
-                    this::onQsExpanded);
-        }
-        if (NotificationThrottleHun.isEnabled()) {
-            mVisualStabilityProvider.addPersistentReorderingBannedListener(
-                    mOnReorderingBannedListener);
-            mVisualStabilityProvider.addPersistentReorderingAllowedListener(
-                    mOnReorderingAllowedListener);
-        }
-    }
-
-    public void setAnimationStateHandler(AnimationStateHandler handler) {
-        mAnimationStateHandler = handler;
-    }
-
-    private void updateResources() {
-        Resources resources = mContext.getResources();
-        mHeadsUpInset = SystemBarUtils.getStatusBarHeight(mContext)
-                + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  Public methods:
-
-    /**
-     * Add a listener to receive callbacks {@link #setHeadsUpAnimatingAway(boolean)}
-     */
-    @Override
-    public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
-        mHeadsUpPhoneListeners.add(listener);
-    }
-
-    /**
-     * Gets the touchable region needed for heads up notifications. Returns null if no touchable
-     * region is required (ie: no heads up notification currently exists).
-     */
-    // TODO(b/347007367): With scene container enabled this method may report outdated regions
-    @Override
-    public @Nullable Region getTouchableRegion() {
-        NotificationEntry topEntry = getTopEntry();
-
-        // This call could be made in an inconsistent state while the pinnedMode hasn't been
-        // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
-        // therefore also check if the topEntry is null.
-        if (!hasPinnedHeadsUp() || topEntry == null) {
-            return null;
-        } else {
-            if (topEntry.rowIsChildInGroup()) {
-                final NotificationEntry groupSummary =
-                        mGroupMembershipManager.getGroupSummary(topEntry);
-                if (groupSummary != null) {
-                    topEntry = groupSummary;
-                }
-            }
-            ExpandableNotificationRow topRow = topEntry.getRow();
-            int[] tmpArray = new int[2];
-            topRow.getLocationOnScreen(tmpArray);
-            int minX = tmpArray[0];
-            int maxX = tmpArray[0] + topRow.getWidth();
-            int height = topRow.getIntrinsicHeight();
-            final boolean stretchToTop = tmpArray[1] <= mHeadsUpInset;
-            mTouchableRegion.set(minX, stretchToTop ? 0 : tmpArray[1], maxX, tmpArray[1] + height);
-            return mTouchableRegion;
-        }
-    }
-
-    /**
-     * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
-     * that a user might have consciously clicked on it.
-     *
-     * @param key the key of the touched notification
-     * @return whether the touch is invalid and should be discarded
-     */
-    @Override
-    public boolean shouldSwallowClick(@NonNull String key) {
-        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
-        return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
-    }
-
-    @Override
-    public void releaseAfterExpansion() {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
-        onExpandingFinished();
-    }
-
-    public void onExpandingFinished() {
-        if (mReleaseOnExpandFinish) {
-            releaseAllImmediately();
-            mReleaseOnExpandFinish = false;
-        } else {
-            for (NotificationEntry entry: getAllEntries().toList()) {
-                entry.setSeenInShade(true);
-            }
-            for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
-                if (isHeadsUpEntry(entry.getKey())) {
-                    // Maybe the heads-up was removed already
-                    removeEntry(entry.getKey(), "onExpandingFinished");
-                }
-            }
-        }
-        mEntriesToRemoveAfterExpand.clear();
-    }
-
-    /**
-     * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
-     * from the list even after a Heads Up Notification is gone.
-     */
-    public void setTrackingHeadsUp(boolean trackingHeadsUp) {
-        mTrackingHeadsUp = trackingHeadsUp;
-    }
-
-    private void onShadeOrQsExpanded(Boolean isExpanded) {
-        if (isExpanded != mIsShadeOrQsExpanded) {
-            mIsShadeOrQsExpanded = isExpanded;
-            if (!SceneContainerFlag.isEnabled() && isExpanded) {
-                mHeadsUpAnimatingAway.setValue(false);
-            }
-        }
-    }
-
-    private void onQsExpanded(Boolean isQsExpanded) {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
-        if (isQsExpanded != mIsQsExpanded) mIsQsExpanded = isQsExpanded;
-    }
-
-    /**
-     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
-     * animating out. This is used to keep the touchable regions in a reasonable state.
-     */
-    @Override
-    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
-        if (headsUpAnimatingAway != mHeadsUpAnimatingAway.getValue()) {
-            for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
-                listener.onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway);
-            }
-            mHeadsUpAnimatingAway.setValue(headsUpAnimatingAway);
-        }
-    }
-
-    @Override
-    public void unpinAll(boolean userUnPinned) {
-        super.unpinAll(userUnPinned);
-    }
-
-    /**
-     * Notifies that a remote input textbox in notification gets active or inactive.
-     *
-     * @param entry             The entry of the target notification.
-     * @param remoteInputActive True to notify active, False to notify inactive.
-     */
-    public void setRemoteInputActive(
-            @NonNull NotificationEntry entry, boolean remoteInputActive) {
-        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
-        if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
-            headsUpEntry.mRemoteInputActive = remoteInputActive;
-            if (ExpandHeadsUpOnInlineReply.isEnabled() && remoteInputActive) {
-                headsUpEntry.mRemoteInputActivatedAtLeastOnce = true;
-            }
-            if (remoteInputActive) {
-                headsUpEntry.cancelAutoRemovalCallbacks("setRemoteInputActive(true)");
-            } else {
-                headsUpEntry.updateEntry(false /* updatePostTime */, "setRemoteInputActive(false)");
-            }
-            onEntryUpdated(headsUpEntry);
-        }
-    }
-
-    /**
-     * Sets whether an entry's guts are exposed and therefore it should stick in the heads up
-     * area if it's pinned until it's hidden again.
-     */
-    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
-        HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
-        if (!(headsUpEntry instanceof HeadsUpEntryPhone)) return;
-        HeadsUpEntryPhone headsUpEntryPhone = (HeadsUpEntryPhone)headsUpEntry;
-        if (entry.isRowPinned() || !gutsShown) {
-            headsUpEntryPhone.setGutsShownPinned(gutsShown);
-        }
-    }
-
-    /**
-     * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
-     * longer.
-     */
-    public void extendHeadsUp() {
-        HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
-        if (topEntry == null) {
-            return;
-        }
-        topEntry.extendPulse();
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  HeadsUpManager public methods overrides and overloads:
-
-    @Override
-    public boolean isTrackingHeadsUp() {
-        return mTrackingHeadsUp;
-    }
-
-    @Override
-    public void snooze() {
-        super.snooze();
-        mReleaseOnExpandFinish = true;
-    }
-
-    public void addSwipedOutNotification(@NonNull String key) {
-        mSwipedOutKeys.add(key);
-    }
-
-    @Override
-    public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
-            boolean animate, @NonNull String reason) {
-        if (animate) {
-            return removeNotification(key, releaseImmediately,
-                    "removeNotification(animate: true), reason: " + reason);
-        } else {
-            mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
-            final boolean removed = removeNotification(key, releaseImmediately,
-                    "removeNotification(animate: false), reason: " + reason);
-            mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
-            return removed;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  Dumpable overrides:
-
-    @Override
-    public void dump(PrintWriter pw, String[] args) {
-        pw.println("HeadsUpManagerPhone state:");
-        dumpInternal(pw, args);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  OnReorderingAllowedListener:
-
-    private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
-        if (NotificationThrottleHun.isEnabled()) {
-            mAvalancheController.setEnableAtRuntime(true);
-            if (mEntriesToRemoveWhenReorderingAllowed.isEmpty()) {
-                return;
-            }
-        }
-        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
-        for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
-            if (entry != null && isHeadsUpEntry(entry.getKey())) {
-                // Maybe the heads-up was removed already
-                removeEntry(entry.getKey(), "mOnReorderingAllowedListener");
-            }
-        }
-        mEntriesToRemoveWhenReorderingAllowed.clear();
-        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
-    };
-
-    private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
-        if (mAvalancheController != null) {
-            // In open shade the first HUN is pinned, and visual stability logic prevents us from
-            // unpinning this first HUN as long as the shade remains open. AvalancheController only
-            // shows the next HUN when the currently showing HUN is unpinned, so we must disable
-            // throttling here so that the incoming HUN stream is not forever paused. This is reset
-            // when reorder becomes allowed.
-            mAvalancheController.setEnableAtRuntime(false);
-
-            // Note that we cannot do the above when
-            // 1) The remove runnable runs because its delay means it may not run before shade close
-            // 2) Reordering is allowed again (when shade closes) because the HUN appear animation
-            // will have started by then
-        }
-    };
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  HeadsUpManager utility (protected) methods overrides:
-
-    @NonNull
-    @Override
-    protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
-        if (NotificationThrottleHun.isEnabled()) {
-            return new HeadsUpEntryPhone(entry);
-        } else {
-            HeadsUpEntryPhone headsUpEntry = mEntryPool.acquire();
-            headsUpEntry.setEntry(entry);
-            return headsUpEntry;
-        }
-    }
-
-    @Override
-    protected void onEntryAdded(HeadsUpEntry headsUpEntry) {
-        super.onEntryAdded(headsUpEntry);
-        updateTopHeadsUpFlow();
-        updateHeadsUpFlow();
-    }
-
-    @Override
-    protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
-        super.onEntryUpdated(headsUpEntry);
-        // no need to update the list here
-        updateTopHeadsUpFlow();
-    }
-
-    @Override
-    protected void onEntryRemoved(HeadsUpEntry headsUpEntry) {
-        super.onEntryRemoved(headsUpEntry);
-        if (!NotificationThrottleHun.isEnabled()) {
-            mEntryPool.release((HeadsUpEntryPhone) headsUpEntry);
-        }
-        updateTopHeadsUpFlow();
-        updateHeadsUpFlow();
-        if (NotificationThrottleHun.isEnabled()) {
-            if (headsUpEntry.mEntry != null) {
-                if (mEntriesToRemoveWhenReorderingAllowed.contains(headsUpEntry.mEntry)) {
-                    mEntriesToRemoveWhenReorderingAllowed.remove(headsUpEntry.mEntry);
-                }
-            }
-        }
-    }
-
-    private void updateTopHeadsUpFlow() {
-        mTopHeadsUpRow.setValue((HeadsUpRowRepository) getTopHeadsUpEntry());
-    }
-
-    private void updateHeadsUpFlow() {
-        mHeadsUpNotificationRows.setValue(new HashSet<>(getHeadsUpEntryPhoneMap().values()));
-    }
-
-    @Override
-    protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
-        boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsShadeOrQsExpanded;
-        if (SceneContainerFlag.isEnabled()) {
-            pin |= mIsQsExpanded;
-        }
-        if (mBypassController.getBypassEnabled()) {
-            pin |= mStatusBarState == StatusBarState.KEYGUARD;
-        }
-        return pin || super.shouldHeadsUpBecomePinned(entry);
-    }
-
-    @Override
-    protected void dumpInternal(PrintWriter pw, String[] args) {
-        super.dumpInternal(pw, args);
-        pw.print("  mBarState=");
-        pw.println(mStatusBarState);
-        pw.print("  mTouchableRegion=");
-        pw.println(mTouchableRegion);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  Private utility methods:
-
-    @NonNull
-    private ArrayMap<String, HeadsUpEntryPhone> getHeadsUpEntryPhoneMap() {
-        //noinspection unchecked
-        return (ArrayMap<String, HeadsUpEntryPhone>) ((ArrayMap) mHeadsUpEntryMap);
-    }
-
-    @Nullable
-    private HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
-        return (HeadsUpEntryPhone) mHeadsUpEntryMap.get(key);
-    }
-
-    @Nullable
-    private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
-        if (SceneContainerFlag.isEnabled()) {
-            return (HeadsUpEntryPhone) mTopHeadsUpRow.getValue();
-        } else {
-            return (HeadsUpEntryPhone) getTopHeadsUpEntry();
-        }
-    }
-
-    @Override
-    public boolean canRemoveImmediately(@NonNull String key) {
-        if (mSwipedOutKeys.contains(key)) {
-            // We always instantly dismiss views being manually swiped out.
-            mSwipedOutKeys.remove(key);
-            return true;
-        }
-
-        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(key);
-        HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
-
-        return headsUpEntry == null || headsUpEntry != topEntry || super.canRemoveImmediately(key);
-    }
-
-    @Override
-    @NonNull
-    public Flow<HeadsUpRowRepository> getTopHeadsUpRow() {
-        return mTopHeadsUpRow;
-    }
-
-    @Override
-    @NonNull
-    public Flow<Set<HeadsUpRowRepository>> getActiveHeadsUpRows() {
-        return mHeadsUpNotificationRows;
-    }
-
-    @Override
-    @NonNull
-    public StateFlow<Boolean> isHeadsUpAnimatingAway() {
-        return mHeadsUpAnimatingAway;
-    }
-
-    @Override
-    public boolean isHeadsUpAnimatingAwayValue() {
-        return mHeadsUpAnimatingAway.getValue();
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  HeadsUpEntryPhone:
-
-    protected class HeadsUpEntryPhone extends BaseHeadsUpManager.HeadsUpEntry implements
-            HeadsUpRowRepository {
-
-        private boolean mGutsShownPinned;
-        private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
-
-        /**
-         * If the time this entry has been on was extended
-         */
-        private boolean extended;
-
-        @Override
-        public boolean isSticky() {
-            return super.isSticky() || mGutsShownPinned;
-        }
-
-        public HeadsUpEntryPhone() {
-            super();
-        }
-
-        public HeadsUpEntryPhone(NotificationEntry entry) {
-            super(entry);
-        }
-
-        @Override
-        @NonNull
-        public String getKey() {
-            return requireEntry().getKey();
-        }
-
-        @Override
-        @NonNull
-        public StateFlow<Boolean> isPinned() {
-            return mIsPinned;
-        }
-
-        @Override
-        protected void setRowPinned(boolean pinned) {
-            // TODO(b/327624082): replace this super call with a ViewBinder
-            super.setRowPinned(pinned);
-            mIsPinned.setValue(pinned);
-        }
-
-        @Override
-        protected void setEntry(@androidx.annotation.NonNull NotificationEntry entry,
-                @androidx.annotation.Nullable Runnable removeRunnable) {
-            super.setEntry(entry, removeRunnable);
-
-            if (NotificationThrottleHun.isEnabled()) {
-                mEntriesToRemoveWhenReorderingAllowed.add(entry);
-                if (!mVisualStabilityProvider.isReorderingAllowed()) {
-                    entry.setSeenInShade(true);
-                }
-            }
-        }
-
-        @Override
-        protected Runnable createRemoveRunnable(NotificationEntry entry) {
-            return () -> {
-                if (!NotificationThrottleHun.isEnabled()
-                        && !mVisualStabilityProvider.isReorderingAllowed()
-                        // We don't want to allow reordering while pulsing, but headsup need to
-                        // time out anyway
-                        && !entry.showingPulsing()) {
-                    mEntriesToRemoveWhenReorderingAllowed.add(entry);
-                    mVisualStabilityProvider.addTemporaryReorderingAllowedListener(
-                            mOnReorderingAllowedListener);
-                } else if (mTrackingHeadsUp) {
-                    mEntriesToRemoveAfterExpand.add(entry);
-                    mLogger.logRemoveEntryAfterExpand(entry);
-                } else if (mVisualStabilityProvider.isReorderingAllowed()
-                        || entry.showingPulsing()) {
-                    removeEntry(entry.getKey(), "createRemoveRunnable");
-                }
-            };
-        }
-
-        @Override
-        public void updateEntry(boolean updatePostTime, String reason) {
-            super.updateEntry(updatePostTime, reason);
-
-            if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
-                mEntriesToRemoveAfterExpand.remove(mEntry);
-            }
-            if (!NotificationThrottleHun.isEnabled()) {
-                if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
-                    mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
-                }
-            }
-        }
-
-        @Override
-        public void setExpanded(boolean expanded) {
-            if (this.mExpanded == expanded) {
-                return;
-            }
-
-            this.mExpanded = expanded;
-            if (expanded) {
-                cancelAutoRemovalCallbacks("setExpanded(true)");
-            } else {
-                updateEntry(false /* updatePostTime */, "setExpanded(false)");
-            }
-        }
-
-        public void setGutsShownPinned(boolean gutsShownPinned) {
-            if (mGutsShownPinned == gutsShownPinned) {
-                return;
-            }
-
-            mGutsShownPinned = gutsShownPinned;
-            if (gutsShownPinned) {
-                cancelAutoRemovalCallbacks("setGutsShownPinned(true)");
-            } else {
-                updateEntry(false /* updatePostTime */, "setGutsShownPinned(false)");
-            }
-        }
-
-        @Override
-        public void reset() {
-            super.reset();
-            mGutsShownPinned = false;
-            extended = false;
-        }
-
-        private void extendPulse() {
-            if (!extended) {
-                extended = true;
-                updateEntry(false, "extendPulse()");
-            }
-        }
-
-        @Override
-        protected long calculateFinishTime() {
-            return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
-        }
-
-        @Override
-        @NonNull
-        public Object getElementKey() {
-            return requireEntry().getRow();
-        }
-
-        private NotificationEntry requireEntry() {
-            /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode();
-            return Objects.requireNonNull(mEntry);
-        }
-    }
-
-    private final StateListener mStatusBarStateListener = new StateListener() {
-        @Override
-        public void onStateChanged(int newState) {
-            boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
-            boolean isKeyguard = newState == StatusBarState.KEYGUARD;
-            mStatusBarState = newState;
-
-            if (wasKeyguard && !isKeyguard && mBypassController.getBypassEnabled()) {
-                ArrayList<String> keysToRemove = new ArrayList<>();
-                for (HeadsUpEntry entry : getHeadsUpEntryList()) {
-                    if (entry.mEntry != null && entry.mEntry.isBubble() && !entry.isSticky()) {
-                        keysToRemove.add(entry.mEntry.getKey());
-                    }
-                }
-                for (String key : keysToRemove) {
-                    removeEntry(key, "mStatusBarStateListener");
-                }
-            }
-        }
-
-        @Override
-        public void onDozingChanged(boolean isDozing) {
-            if (!isDozing) {
-                // Let's make sure all huns we got while dozing time out within the normal timeout
-                // duration. Otherwise they could get stuck for a very long time
-                for (HeadsUpEntry entry : getHeadsUpEntryList()) {
-                    entry.updateEntry(true /* updatePostTime */, "onDozingChanged(false)");
-                }
-            }
-        }
-    };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
index dc8ff63..90212ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
@@ -27,13 +27,13 @@
 import javax.inject.Inject
 
 /**
- * A small coordinator which updates the notif stack (the view layer which holds notifications)
- * with high-level data after the stack is populated with the final entries.
+ * A small coordinator which updates the notif stack (the view layer which holds notifications) with
+ * high-level data after the stack is populated with the final entries.
  */
 @CoordinatorScope
-class DataStoreCoordinator @Inject internal constructor(
-    private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl
-) : CoreCoordinator {
+class DataStoreCoordinator
+@Inject
+internal constructor(private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl) : CoreCoordinator {
 
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addOnAfterRenderListListener { entries, _ -> onAfterRenderList(entries) }
@@ -61,4 +61,4 @@
                 }
             }
         }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index e9292f8..32de65b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -43,8 +43,7 @@
     private val groupExpansionManagerImpl: GroupExpansionManagerImpl,
     private val renderListInteractor: RenderNotificationListInteractor,
     private val activeNotificationsInteractor: ActiveNotificationsInteractor,
-    private val sensitiveNotificationProtectionController:
-        SensitiveNotificationProtectionController,
+    private val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController,
 ) : Coordinator {
 
     override fun attach(pipeline: NotifPipeline) {
@@ -52,7 +51,7 @@
         groupExpansionManagerImpl.attach(pipeline)
     }
 
-    fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
+    private fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
         traceSection("StackCoordinator.onAfterRenderList") {
             val notifStats = calculateNotifStats(entries)
             if (FooterViewRefactor.isEnabled) {
@@ -78,13 +77,13 @@
             val isSilent = section.bucket == BUCKET_SILENT
             // NOTE: NotificationEntry.isClearable will internally check group children to ensure
             //  the group itself definitively clearable.
-            val isClearable = !isSensitiveContentProtectionActive && entry.isClearable
-                    && !entry.isSensitive.value
+            val isClearable =
+                !isSensitiveContentProtectionActive && entry.isClearable && !entry.isSensitive.value
             when {
                 isSilent && isClearable -> hasClearableSilentNotifs = true
                 isSilent && !isClearable -> hasNonClearableSilentNotifs = true
                 !isSilent && isClearable -> hasClearableAlertingNotifs = true
-                !isSilent && !isClearable -> hasNonClearableAlertingNotifs = true
+                else -> hasNonClearableAlertingNotifs = true
             }
         }
         return NotifStats(
@@ -92,7 +91,7 @@
             hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs,
             hasClearableAlertingNotifs = hasClearableAlertingNotifs,
             hasNonClearableSilentNotifs = hasNonClearableSilentNotifs,
-            hasClearableSilentNotifs = hasClearableSilentNotifs
+            hasClearableSilentNotifs = hasClearableSilentNotifs,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
index 1ea574b..410b78b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
@@ -21,15 +21,15 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 
 /**
- * This interface and the interfaces it returns define the main API surface that must be
- * implemented by the view implementation.  The term "render" is used to indicate a handoff
- * to the view system, whether that be to attach views to the hierarchy or to update independent
- * view models, data stores, or adapters.
+ * This interface and the interfaces it returns define the main API surface that must be implemented
+ * by the view implementation. The term "render" is used to indicate a handoff to the view system,
+ * whether that be to attach views to the hierarchy or to update independent view models, data
+ * stores, or adapters.
  */
 interface NotifViewRenderer {
 
     /**
-     * Hand off the list of notifications to the view implementation.  This may attach views to the
+     * Hand off the list of notifications to the view implementation. This may attach views to the
      * hierarchy or simply update an independent datastore, but once called, the implementer myst
      * also ensure that future calls to [getStackController], [getGroupController], and
      * [getRowController] will provide valid results.
@@ -37,21 +37,21 @@
     fun onRenderList(notifList: List<ListEntry>)
 
     /**
-     * Provides an interface for the pipeline to update the overall shade.
-     * This will be called at most once for each time [onRenderList] is called.
+     * Provides an interface for the pipeline to update the overall shade. This will be called at
+     * most once for each time [onRenderList] is called.
      */
     fun getStackController(): NotifStackController
 
     /**
-     * Provides an interface for the pipeline to update individual groups.
-     * This will be called at most once for each group in the most recent call to [onRenderList].
+     * Provides an interface for the pipeline to update individual groups. This will be called at
+     * most once for each group in the most recent call to [onRenderList].
      */
     fun getGroupController(group: GroupEntry): NotifGroupController
 
     /**
-     * Provides an interface for the pipeline to update individual entries.
-     * This will be called at most once for each entry in the most recent call to [onRenderList].
-     * This includes top level entries, group summaries, and group children.
+     * Provides an interface for the pipeline to update individual entries. This will be called at
+     * most once for each entry in the most recent call to [onRenderList]. This includes top level
+     * entries, group summaries, and group children.
      */
     fun getRowController(entry: NotificationEntry): NotifRowController
 
@@ -62,8 +62,8 @@
      * logic now that all data from the pipeline is known to have been set for this execution.
      *
      * When this is called, the view system can expect that no more calls will be made to the
-     * getters on this interface until after the next call to [onRenderList].  Additionally, there
+     * getters on this interface until after the next call to [onRenderList]. Additionally, there
      * should be no further calls made on the objects previously returned by those getters.
      */
     fun onDispatchComplete() {}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
index 9b55210..9d3b098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.render
 
+import com.android.app.tracing.traceSection
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -26,7 +27,6 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderGroupListener
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
-import com.android.app.tracing.traceSection
 import javax.inject.Inject
 
 /**
@@ -77,16 +77,17 @@
         onAfterRenderEntryListeners.add(listener)
     }
 
-    override fun dumpPipeline(d: PipelineDumper) = with(d) {
-        dump("viewRenderer", viewRenderer)
-        dump("onAfterRenderListListeners", onAfterRenderListListeners)
-        dump("onAfterRenderGroupListeners", onAfterRenderGroupListeners)
-        dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners)
-    }
+    override fun dumpPipeline(d: PipelineDumper) =
+        with(d) {
+            dump("viewRenderer", viewRenderer)
+            dump("onAfterRenderListListeners", onAfterRenderListListeners)
+            dump("onAfterRenderGroupListeners", onAfterRenderGroupListeners)
+            dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners)
+        }
 
     private fun dispatchOnAfterRenderList(
         viewRenderer: NotifViewRenderer,
-        entries: List<ListEntry>
+        entries: List<ListEntry>,
     ) {
         traceSection("RenderStageManager.dispatchOnAfterRenderList") {
             val stackController = viewRenderer.getStackController()
@@ -98,7 +99,7 @@
 
     private fun dispatchOnAfterRenderGroups(
         viewRenderer: NotifViewRenderer,
-        entries: List<ListEntry>
+        entries: List<ListEntry>,
     ) {
         traceSection("RenderStageManager.dispatchOnAfterRenderGroups") {
             if (onAfterRenderGroupListeners.isEmpty()) {
@@ -115,7 +116,7 @@
 
     private fun dispatchOnAfterRenderEntries(
         viewRenderer: NotifViewRenderer,
-        entries: List<ListEntry>
+        entries: List<ListEntry>,
     ) {
         traceSection("RenderStageManager.dispatchOnAfterRenderEntries") {
             if (onAfterRenderEntryListeners.isEmpty()) {
@@ -131,8 +132,8 @@
     }
 
     /**
-     * Performs a forward, depth-first traversal of the list where the group's summary
-     * immediately precedes the group's children.
+     * Performs a forward, depth-first traversal of the list where the group's summary immediately
+     * precedes the group's children.
      */
     private inline fun List<ListEntry>.forEachNotificationEntry(
         action: (NotificationEntry) -> Unit
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index 63c9e8b..cf4fb25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -16,16 +16,11 @@
 package com.android.systemui.statusbar.notification.data
 
 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
 import dagger.Binds
 import dagger.Module
 
-@Module(
-    includes =
-        [
-            NotificationSettingsRepositoryModule::class,
-        ]
-)
+@Module(includes = [NotificationSettingsRepositoryModule::class])
 interface NotificationDataLayerModule {
-    @Binds fun bindHeadsUpNotificationRepository(impl: HeadsUpManagerPhone): HeadsUpRepository
+    @Binds fun bindHeadsUpNotificationRepository(impl: BaseHeadsUpManager): HeadsUpRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
index 45d1034..2b9e493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
@@ -66,7 +66,7 @@
      * Map of notification key to rank, where rank is the 0-based index of the notification on the
      * system server, meaning that in the unfiltered flattened list of notification entries.
      */
-    val rankingsMap: Map<String, Int> = emptyMap()
+    val rankingsMap: Map<String, Int> = emptyMap(),
 ) {
     operator fun get(key: Key): ActiveNotificationEntryModel? {
         return when (key) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
index 8079ce5..4ea597a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt
@@ -17,17 +17,15 @@
 package com.android.systemui.statusbar.notification.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
 import javax.inject.Inject
 
 /** Interactor for notification alerting. */
 @SysUISingleton
 class NotificationAlertsInteractor
 @Inject
-constructor(
-    private val disableFlagsRepository: DisableFlagsRepository,
-) {
+constructor(private val disableFlagsInteractor: DisableFlagsInteractor) {
     /** Returns true if notification alerts are allowed. */
     fun areNotificationAlertsEnabled(): Boolean =
-        disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled()
+        disableFlagsInteractor.disableFlags.value.areNotificationAlertsEnabled()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 76e228b..2c5d9c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -38,6 +38,8 @@
     )
 
     fun resetUserExpandedStates()
+
     fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption)
+
     fun getActiveNotificationsCount(): Int
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 1677418..ea6a60b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -129,7 +129,7 @@
         } else {
             notificationListener.snoozeNotification(
                 sbn.key,
-                snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong()
+                snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong(),
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 65ba6de..148b3f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -28,9 +28,9 @@
 /**
  * Implementation of [NotificationsController] that's used when notifications rendering is disabled.
  */
-class NotificationsControllerStub @Inject constructor(
-    private val notificationListener: NotificationListener
-) : NotificationsController {
+class NotificationsControllerStub
+@Inject
+constructor(private val notificationListener: NotificationListener) : NotificationsController {
 
     override fun initialize(
         presenter: NotificationPresenter,
@@ -43,11 +43,9 @@
         notificationListener.registerAsSystemService()
     }
 
-    override fun resetUserExpandedStates() {
-    }
+    override fun resetUserExpandedStates() {}
 
-    override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {
-    }
+    override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {}
 
     override fun getActiveNotificationsCount(): Int {
         return 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 08d177f..d1de6be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1543,7 +1543,6 @@
         setDragController(null);
         mGroupParentWhenDismissed = mNotificationParent;
         mChildAfterViewWhenDismissed = null;
-        mEntry.getIcons().getStatusBarIcon().setDismissed();
         if (isChildInGroup()) {
             List<ExpandableNotificationRow> notificationChildren =
                     mNotificationParent.getAttachedChildren();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9166e7e..786d7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -573,8 +573,29 @@
             return;
         }
 
-        mUiEventLogger.log(
-                NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN);
+        final StatusBarNotification containingRowSbn = getContainingRowSbn();
+        if (containingRowSbn == null) {
+            return;
+        }
+
+        mUiEventLogger.logWithInstanceId(
+                NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN,
+                containingRowSbn.getUid(),
+                containingRowSbn.getPackageName(),
+                containingRowSbn.getInstanceId());
+    }
+
+    @Nullable
+    private StatusBarNotification getContainingRowSbn() {
+        if (mContainingNotification == null) {
+            return null;
+        }
+        final NotificationEntry entry = mContainingNotification.getEntry();
+        if (entry == null) {
+            return null;
+        }
+
+        return entry.getSbn();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
index 7919c84..83551e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -17,12 +17,12 @@
 package com.android.systemui.statusbar.phone
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
+import com.android.systemui.statusbar.policy.BaseHeadsUpManager
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import dagger.Binds
 import dagger.Module
 
 @Module
 interface HeadsUpModule {
-    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: HeadsUpManagerPhone): HeadsUpManager
+    @Binds @SysUISingleton fun bindsHeadsUpManager(hum: BaseHeadsUpManager): HeadsUpManager
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
index 13ac321..f3d5139 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
@@ -113,34 +113,38 @@
         }
 
     private val showIcon =
-        canShowIcon
-            .flatMapLatest { canShow ->
-                if (!canShow) {
-                    flowOf(false)
-                } else {
-                    combine(
-                        shouldShowIconForOosAfterHysteresis,
-                        interactor.connectionState,
-                        interactor.isWifiActive,
-                        airplaneModeRepository.isAirplaneMode,
-                    ) { showForOos, connectionState, isWifiActive, isAirplaneMode ->
-                        if (isWifiActive || isAirplaneMode) {
-                            false
-                        } else {
-                            showForOos ||
-                                connectionState == SatelliteConnectionState.On ||
-                                connectionState == SatelliteConnectionState.Connected
+        if (interactor.isOpportunisticSatelliteIconEnabled) {
+            canShowIcon
+                .flatMapLatest { canShow ->
+                    if (!canShow) {
+                        flowOf(false)
+                    } else {
+                        combine(
+                            shouldShowIconForOosAfterHysteresis,
+                            interactor.connectionState,
+                            interactor.isWifiActive,
+                            airplaneModeRepository.isAirplaneMode,
+                        ) { showForOos, connectionState, isWifiActive, isAirplaneMode ->
+                            if (isWifiActive || isAirplaneMode) {
+                                false
+                            } else {
+                                showForOos ||
+                                    connectionState == SatelliteConnectionState.On ||
+                                    connectionState == SatelliteConnectionState.Connected
+                            }
                         }
                     }
                 }
+                .distinctUntilChanged()
+                .logDiffsForTable(
+                    tableLog,
+                    columnPrefix = "vm",
+                    columnName = COL_VISIBLE,
+                    initialValue = false,
+                )
+            } else {
+                flowOf(false)
             }
-            .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLog,
-                columnPrefix = "vm",
-                columnName = COL_VISIBLE,
-                initialValue = false,
-            )
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     override val icon: StateFlow<Icon?> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
index 9164da7..b2a0272 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.pipeline.shared.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.model.StatusBarDisableFlagsVisibilityModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -30,13 +30,13 @@
 @SysUISingleton
 class CollapsedStatusBarInteractor
 @Inject
-constructor(disableFlagsRepository: DisableFlagsRepository) {
+constructor(DisableFlagsInteractor: DisableFlagsInteractor) {
     /**
      * The visibilities of various status bar child views, based only on the information we received
      * from disable flags.
      */
     val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> =
-        disableFlagsRepository.disableFlags.map {
+        DisableFlagsInteractor.disableFlags.map {
             StatusBarDisableFlagsVisibilityModel(
                 isClockAllowed = it.isClockEnabled,
                 areNotificationIconsAllowed = it.areNotificationIconsEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index c7b6be3..a72c83e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -92,8 +92,7 @@
 
     private var wifiPickerTracker: WifiPickerTracker? = null
 
-    @VisibleForTesting
-    val selectedUserContext: Flow<Context> =
+    private val selectedUserContext: Flow<Context> =
         userRepository.selectedUserInfo.map {
             applicationContext.createContextAsUser(UserHandle.of(it.id), /* flags= */ 0)
         }
@@ -112,8 +111,7 @@
             selectedUserContext
                 .flatMapLatest { currentContext
                     -> // flatMapLatest because when selectedUserContext emits a new value, we want
-                    // to
-                    // re-create a whole flow
+                    // to re-create a whole flow
                     callbackFlow {
                             val callback =
                                 object : WifiPickerTracker.WifiPickerTrackerCallback {
@@ -132,20 +130,16 @@
                                                 .map { it.toWifiNetworkModel() }
 
                                         // [WifiPickerTracker.connectedWifiEntry] will return the
-                                        // same
-                                        // instance but with updated internals. For example, when
-                                        // its
-                                        // validation status changes from false to true, the same
-                                        // instance is re-used but with the validated field updated.
+                                        // same instance but with updated internals. For example,
+                                        // when its validation status changes from false to true,
+                                        // the same instance is re-used but with the validated
+                                        // field updated.
                                         //
                                         // Because it's the same instance, the flow won't re-emit
-                                        // the
-                                        // value (even though the internals have changed). So, we
-                                        // need
-                                        // to transform it into our internal model immediately.
-                                        // [toWifiNetworkModel] always returns a new instance, so
-                                        // the
-                                        // flow is guaranteed to emit.
+                                        // the value (even though the internals have changed). So,
+                                        // we need to transform it into our internal model
+                                        // immediately. [toWifiNetworkModel] always returns a new
+                                        // instance, so the flow is guaranteed to emit.
                                         send(
                                             newPrimaryNetwork =
                                                 connectedEntry?.toPrimaryWifiNetworkModel()
@@ -235,20 +229,15 @@
                                             .map { it.toWifiNetworkModel() }
 
                                     // [WifiPickerTracker.connectedWifiEntry] will return the same
-                                    // instance
-                                    // but with updated internals. For example, when its validation
-                                    // status
-                                    // changes from false to true, the same instance is re-used but
-                                    // with the
-                                    // validated field updated.
+                                    // instance but with updated internals. For example, when its
+                                    // validation status changes from false to true, the same
+                                    // instance is re-used but with the validated field updated.
                                     //
                                     // Because it's the same instance, the flow won't re-emit the
-                                    // value
-                                    // (even though the internals have changed). So, we need to
-                                    // transform it
-                                    // into our internal model immediately. [toWifiNetworkModel]
-                                    // always
-                                    // returns a new instance, so the flow is guaranteed to emit.
+                                    // value (even though the internals have changed). So, we need
+                                    // to transform it into our internal model immediately.
+                                    // [toWifiNetworkModel] always returns a new instance, so the
+                                    // flow is guaranteed to emit.
                                     send(
                                         newPrimaryNetwork =
                                             connectedEntry?.toPrimaryWifiNetworkModel()
@@ -292,12 +281,10 @@
                                 .create(applicationContext, lifecycle, callback, "WifiRepository")
                                 .apply {
                                     // By default, [WifiPickerTracker] will scan to see all
-                                    // available wifi
-                                    // networks in the area. Because SysUI only needs to display the
-                                    // **connected** network, we don't need scans to be running (and
-                                    // in fact,
-                                    // running scans is costly and should be avoided whenever
-                                    // possible).
+                                    // available wifi networks in the area. Because SysUI only
+                                    // needs to display the **connected** network, we don't
+                                    // need scans to be running (and in fact, running scans is
+                                    // costly and should be avoided whenever possible).
                                     this?.disableScanning()
                                 }
                         // The lifecycle must be STARTED in order for the callback to receive
@@ -382,16 +369,11 @@
 
     private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
         // WifiEntry instance values aren't guaranteed to be stable between method calls
-        // because
-        // WifiPickerTracker is continuously updating the same object. Save the level in a
-        // local
-        // variable so that checking the level validity here guarantees that the level will
-        // still be
-        // valid when we create the `WifiNetworkModel.Active` instance later. Otherwise, the
-        // level
-        // could be valid here but become invalid later, and `WifiNetworkModel.Active` will
-        // throw
-        // an exception. See b/362384551.
+        // because WifiPickerTracker is continuously updating the same object. Save the
+        // level in a local variable so that checking the level validity here guarantees
+        // that the level will still be valid when we create the `WifiNetworkModel.Active`
+        // instance later. Otherwise, the level could be valid here but become invalid
+        // later, and `WifiNetworkModel.Active` will throw an exception. See b/362384551.
 
         return WifiNetworkModel.CarrierMerged.of(
             subscriptionId = this.subscriptionId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
index 4284c19..f6f567f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java
@@ -16,33 +16,48 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Region;
 import android.os.Handler;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pools;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
+import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
+import com.android.systemui.statusbar.notification.collection.provider.OnReorderingBannedListener;
+import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
 import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.ListenerSet;
 import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.SystemClock;
 
@@ -50,14 +65,27 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Stack;
 import java.util.stream.Stream;
 
+import javax.inject.Inject;
+
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
 /**
  * A manager which handles heads up notifications which is a special mode where
  * they simply peek from the top of the screen.
  */
-public abstract class BaseHeadsUpManager implements HeadsUpManager {
+@SysUISingleton
+public class BaseHeadsUpManager
+        implements HeadsUpManager, HeadsUpRepository, OnHeadsUpChangedListener {
     private static final String TAG = "BaseHeadsUpManager";
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
 
@@ -74,7 +102,11 @@
     private final AccessibilityManagerWrapper mAccessibilityMgr;
 
     private final UiEventLogger mUiEventLogger;
-    private final AvalancheController mAvalancheController;
+    private AvalancheController mAvalancheController;
+    private final KeyguardBypassController mBypassController;
+    private final GroupMembershipManager mGroupMembershipManager;
+    private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
+    private final VisualStabilityProvider mVisualStabilityProvider;
 
     protected final SystemClock mSystemClock;
     protected final ArrayMap<String, HeadsUpEntry> mHeadsUpEntryMap = new ArrayMap<>();
@@ -84,6 +116,53 @@
     protected int mAutoDismissTime;
     protected DelayableExecutor mExecutor;
 
+    @VisibleForTesting
+    public final int mExtensionTime;
+
+    // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
+    private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
+            StateFlowKt.MutableStateFlow(null);
+    private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =
+            StateFlowKt.MutableStateFlow(new HashSet<>());
+    private final MutableStateFlow<Boolean> mHeadsUpAnimatingAway =
+            StateFlowKt.MutableStateFlow(false);
+    private final HashSet<String> mSwipedOutKeys = new HashSet<>();
+    private final HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+    @VisibleForTesting
+    public final ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
+            = new ArraySet<>();
+
+    private boolean mReleaseOnExpandFinish;
+    private boolean mTrackingHeadsUp;
+    private boolean mIsShadeOrQsExpanded;
+    private boolean mIsQsExpanded;
+    private int mStatusBarState;
+    private AnimationStateHandler mAnimationStateHandler;
+    private int mHeadsUpInset;
+
+    // Used for determining the region for touch interaction
+    private final Region mTouchableRegion = new Region();
+
+    private final Pools.Pool<HeadsUpEntry> mEntryPool = new Pools.Pool<>() {
+        private final Stack<HeadsUpEntry> mPoolObjects = new Stack<>();
+
+        @Override
+        public HeadsUpEntry acquire() {
+            NotificationThrottleHun.assertInLegacyMode();
+            if (!mPoolObjects.isEmpty()) {
+                return mPoolObjects.pop();
+            }
+            return new HeadsUpEntry();
+        }
+
+        @Override
+        public boolean release(@NonNull HeadsUpEntry instance) {
+            NotificationThrottleHun.assertInLegacyMode();
+            mPoolObjects.push(instance);
+            return true;
+        }
+    };
+
     /**
      * Enum entry for notification peek logged from this class.
      */
@@ -100,14 +179,23 @@
         }
     }
 
-    public BaseHeadsUpManager(@NonNull final Context context,
+    @Inject
+    public BaseHeadsUpManager(
+            @NonNull final Context context,
             HeadsUpManagerLogger logger,
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController bypassController,
+            GroupMembershipManager groupMembershipManager,
+            VisualStabilityProvider visualStabilityProvider,
+            ConfigurationController configurationController,
             @Main Handler handler,
             GlobalSettings globalSettings,
             SystemClock systemClock,
             @Main DelayableExecutor executor,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
             UiEventLogger uiEventLogger,
+            JavaAdapter javaAdapter,
+            ShadeInteractor shadeInteractor,
             AvalancheController avalancheController) {
         mLogger = logger;
         mExecutor = executor;
@@ -117,12 +205,16 @@
         mUiEventLogger = uiEventLogger;
         mAvalancheController = avalancheController;
         mAvalancheController.setBaseEntryMapStr(this::getEntryMapStr);
+        mBypassController = bypassController;
+        mGroupMembershipManager = groupMembershipManager;
+        mVisualStabilityProvider = visualStabilityProvider;
         Resources resources = context.getResources();
         mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
                 ? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
         mStickyForSomeTimeAutoDismissTime = resources.getInteger(
                 R.integer.sticky_heads_up_notification_time);
         mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
+        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
         mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
         mSnoozedPackages = new ArrayMap<>();
         int defaultSnoozeLengthMs =
@@ -145,11 +237,38 @@
                 globalSettings.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS),
                 /* notifyForDescendants = */ false,
                 settingsObserver);
+
+        statusBarStateController.addCallback(mStatusBarStateListener);
+        updateResources();
+        configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+            @Override
+            public void onDensityOrFontScaleChanged() {
+                updateResources();
+            }
+
+            @Override
+            public void onThemeChanged() {
+                updateResources();
+            }
+        });
+        javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(),
+                this::onShadeOrQsExpanded);
+        if (SceneContainerFlag.isEnabled()) {
+            javaAdapter.alwaysCollectFlow(shadeInteractor.isQsExpanded(),
+                    this::onQsExpanded);
+        }
+        if (NotificationThrottleHun.isEnabled()) {
+            mVisualStabilityProvider.addPersistentReorderingBannedListener(
+                    mOnReorderingBannedListener);
+            mVisualStabilityProvider.addPersistentReorderingAllowedListener(
+                    mOnReorderingAllowedListener);
+        }
     }
 
     /**
      * Adds an OnHeadUpChangedListener to observe events.
      */
+    @Override
     public void addListener(@NonNull OnHeadsUpChangedListener listener) {
         mListeners.addIfAbsent(listener);
     }
@@ -157,11 +276,31 @@
     /**
      * Removes the OnHeadUpChangedListener from the observer list.
      */
+    @Override
     public void removeListener(@NonNull OnHeadsUpChangedListener listener) {
         mListeners.remove(listener);
     }
 
     /**
+     * Add a listener to receive callbacks {@link #setHeadsUpAnimatingAway(boolean)}
+     */
+    @Override
+    public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+        mHeadsUpPhoneListeners.add(listener);
+    }
+
+    @Override
+    public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+        mAnimationStateHandler = handler;
+    }
+
+    private void updateResources() {
+        Resources resources = mContext.getResources();
+        mHeadsUpInset = SystemBarUtils.getStatusBarHeight(mContext)
+                + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding);
+    }
+
+    /**
      * Called when posting a new notification that should appear on screen.
      * Adds the notification to be managed.
      * @param entry entry to show
@@ -188,14 +327,24 @@
         mAvalancheController.update(headsUpEntry, runnable, "showNotification");
     }
 
-    /**
-     * Try to remove the notification.  May not succeed if the notification has not been shown long
-     * enough and needs to be kept around.
-     * @param key the key of the notification to remove
-     * @param releaseImmediately force a remove regardless of earliest removal time
-     * @param reason reason for removing the notification
-     * @return true if notification is removed, false otherwise
-     */
+    @Override
+    public boolean removeNotification(
+            @NonNull String key,
+            boolean releaseImmediately,
+            boolean animate,
+            @NonNull String reason) {
+        if (animate) {
+            return removeNotification(key, releaseImmediately,
+                    "removeNotification(animate: true), reason: " + reason);
+        } else {
+            mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
+            final boolean removed = removeNotification(key, releaseImmediately,
+                    "removeNotification(animate: false), reason: " + reason);
+            mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
+            return removed;
+        }
+    }
+
     @Override
     public boolean removeNotification(@NotNull String key, boolean releaseImmediately,
             @NonNull String reason) {
@@ -261,6 +410,42 @@
         }
     }
 
+    @Override
+    public void setTrackingHeadsUp(boolean trackingHeadsUp) {
+        mTrackingHeadsUp = trackingHeadsUp;
+    }
+
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        BaseHeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+        return entry != null && mSystemClock.elapsedRealtime() < entry.mPostTime;
+    }
+
+    @Override
+    public void releaseAfterExpansion() {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+        onExpandingFinished();
+    }
+
+    @Override
+    public void onExpandingFinished() {
+        if (mReleaseOnExpandFinish) {
+            releaseAllImmediately();
+            mReleaseOnExpandFinish = false;
+        } else {
+            for (NotificationEntry entry : getAllEntries().toList()) {
+                entry.setSeenInShade(true);
+            }
+            for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
+                if (isHeadsUpEntry(entry.getKey())) {
+                    // Maybe the heads-up was removed already
+                    removeEntry(entry.getKey(), "onExpandingFinished");
+                }
+            }
+        }
+        mEntriesToRemoveAfterExpand.clear();
+    }
+
     /**
      * Clears all managed notifications.
      */
@@ -339,10 +524,19 @@
         return 0;
     }
 
+    @VisibleForTesting
     protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
-        if (entry == null) {
-            return false;
+        boolean pin = mStatusBarState == StatusBarState.SHADE && !mIsShadeOrQsExpanded;
+        if (SceneContainerFlag.isEnabled()) {
+            pin |= mIsQsExpanded;
         }
+        if (mBypassController.getBypassEnabled()) {
+            pin |= mStatusBarState == StatusBarState.KEYGUARD;
+        }
+        if (pin) {
+            return true;
+        }
+
         final HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
         if (headsUpEntry == null) {
             // This should not happen since shouldHeadsUpBecomePinned is always called after adding
@@ -392,10 +586,6 @@
         }
     }
 
-    public @InflationFlag int getContentFlag() {
-        return FLAG_CONTENT_VIEW_HEADS_UP;
-    }
-
     /**
      * Manager-specific logic that should occur when an entry is added.
      * @param headsUpEntry entry added
@@ -410,6 +600,8 @@
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, true);
         }
+        updateTopHeadsUpFlow();
+        updateHeadsUpFlow();
     }
 
     /**
@@ -466,11 +658,60 @@
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, false);
         }
+        if (!NotificationThrottleHun.isEnabled()) {
+            mEntryPool.release(headsUpEntry);
+        }
+        updateTopHeadsUpFlow();
+        updateHeadsUpFlow();
+        if (NotificationThrottleHun.isEnabled()) {
+            if (headsUpEntry.mEntry != null) {
+                if (mEntriesToRemoveWhenReorderingAllowed.contains(headsUpEntry.mEntry)) {
+                    mEntriesToRemoveWhenReorderingAllowed.remove(headsUpEntry.mEntry);
+                }
+            }
+        }
+    }
+
+    private void updateTopHeadsUpFlow() {
+        mTopHeadsUpRow.setValue((HeadsUpRowRepository) getTopHeadsUpEntry());
+    }
+
+    private void updateHeadsUpFlow() {
+        mHeadsUpNotificationRows.setValue(new HashSet<>(getHeadsUpEntryPhoneMap().values()));
+    }
+
+    @Override
+    @NonNull
+    public Flow<HeadsUpRowRepository> getTopHeadsUpRow() {
+        return mTopHeadsUpRow;
+    }
+
+    @Override
+    @NonNull
+    public Flow<Set<HeadsUpRowRepository>> getActiveHeadsUpRows() {
+        return mHeadsUpNotificationRows;
+    }
+
+    @Override
+    @NonNull
+    public StateFlow<Boolean> isHeadsUpAnimatingAway() {
+        return mHeadsUpAnimatingAway;
+    }
+
+    @Override
+    public boolean isHeadsUpAnimatingAwayValue() {
+        return mHeadsUpAnimatingAway.getValue();
+    }
+
+    @NonNull
+    private ArrayMap<String, HeadsUpEntry> getHeadsUpEntryPhoneMap() {
+        return mHeadsUpEntryMap;
     }
 
     /**
      * Called to notify the listeners that the HUN animating away animation has ended.
      */
+    @Override
     public void onEntryAnimatingAwayEnded(@NonNull NotificationEntry entry) {
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpAnimatingAwayEnded(entry);
@@ -484,6 +725,8 @@
      * @param headsUpEntry entry updated
      */
     protected void onEntryUpdated(HeadsUpEntry headsUpEntry) {
+        // no need to update the list here
+        updateTopHeadsUpFlow();
     }
 
     protected void updatePinnedMode() {
@@ -521,6 +764,7 @@
     /**
      * Snoozes all current Heads Up Notifications.
      */
+    @Override
     public void snooze() {
         List<String> keySet = new ArrayList<>(mHeadsUpEntryMap.keySet());
         keySet.addAll(mAvalancheController.getWaitingKeys());
@@ -534,6 +778,7 @@
             mLogger.logPackageSnoozed(snoozeKey);
             mSnoozedPackages.put(snoozeKey, mSystemClock.elapsedRealtime() + mSnoozeLengthMs);
         }
+        mReleaseOnExpandFinish = true;
     }
 
     @NonNull
@@ -541,6 +786,11 @@
         return user + "," + packageName;
     }
 
+    @Override
+    public void addSwipedOutNotification(@NonNull String key) {
+        mSwipedOutKeys.add(key);
+    }
+
     @Nullable
     protected HeadsUpEntry getHeadsUpEntry(@NonNull String key) {
         if (mHeadsUpEntryMap.containsKey(key)) {
@@ -597,6 +847,59 @@
     }
 
     @Override
+    public @Nullable Region getTouchableRegion() {
+        NotificationEntry topEntry = getTopEntry();
+
+        // This call could be made in an inconsistent state while the pinnedMode hasn't been
+        // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
+        // therefore also check if the topEntry is null.
+        if (!hasPinnedHeadsUp() || topEntry == null) {
+            return null;
+        } else {
+            if (topEntry.rowIsChildInGroup()) {
+                final NotificationEntry groupSummary =
+                        mGroupMembershipManager.getGroupSummary(topEntry);
+                if (groupSummary != null) {
+                    topEntry = groupSummary;
+                }
+            }
+            ExpandableNotificationRow topRow = topEntry.getRow();
+            int[] tmpArray = new int[2];
+            topRow.getLocationOnScreen(tmpArray);
+            int minX = tmpArray[0];
+            int maxX = tmpArray[0] + topRow.getWidth();
+            int height = topRow.getIntrinsicHeight();
+            final boolean stretchToTop = tmpArray[1] <= mHeadsUpInset;
+            mTouchableRegion.set(minX, stretchToTop ? 0 : tmpArray[1], maxX, tmpArray[1] + height);
+            return mTouchableRegion;
+        }
+    }
+
+    @Override
+    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+        if (headsUpAnimatingAway != mHeadsUpAnimatingAway.getValue()) {
+            for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
+                listener.onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway);
+            }
+            mHeadsUpAnimatingAway.setValue(headsUpAnimatingAway);
+        }
+    }
+
+    private void onShadeOrQsExpanded(Boolean isExpanded) {
+        if (isExpanded != mIsShadeOrQsExpanded) {
+            mIsShadeOrQsExpanded = isExpanded;
+            if (!SceneContainerFlag.isEnabled() && isExpanded) {
+                mHeadsUpAnimatingAway.setValue(false);
+            }
+        }
+    }
+
+    private void onQsExpanded(Boolean isQsExpanded) {
+        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+        if (isQsExpanded != mIsQsExpanded) mIsQsExpanded = isQsExpanded;
+    }
+
+    @Override
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("HeadsUpManager state:");
         dumpInternal(pw, args);
@@ -616,6 +919,10 @@
             pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));
             pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
         }
+        pw.print("  mBarState=");
+        pw.println(mStatusBarState);
+        pw.print("  mTouchableRegion=");
+        pw.println(mTouchableRegion);
     }
 
     /**
@@ -639,6 +946,7 @@
      * Unpins all pinned Heads Up Notifications.
      * @param userUnPinned The unpinned action is trigger by user real operation.
      */
+    @Override
     public void unpinAll(boolean userUnPinned) {
         for (String key : mHeadsUpEntryMap.keySet()) {
             HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
@@ -662,13 +970,59 @@
         }
     }
 
-    /**
-     * Returns the value of the tracking-heads-up flag. See the doc of {@code setTrackingHeadsUp} as
-     * well.
-     */
+    @Override
+    public void setRemoteInputActive(
+            @NonNull NotificationEntry entry, boolean remoteInputActive) {
+        HeadsUpEntry headsUpEntry = getHeadsUpEntryPhone(entry.getKey());
+        if (headsUpEntry != null && headsUpEntry.mRemoteInputActive != remoteInputActive) {
+            headsUpEntry.mRemoteInputActive = remoteInputActive;
+            if (ExpandHeadsUpOnInlineReply.isEnabled() && remoteInputActive) {
+                headsUpEntry.mRemoteInputActivatedAtLeastOnce = true;
+            }
+            if (remoteInputActive) {
+                headsUpEntry.cancelAutoRemovalCallbacks("setRemoteInputActive(true)");
+            } else {
+                headsUpEntry.updateEntry(false /* updatePostTime */, "setRemoteInputActive(false)");
+            }
+            onEntryUpdated(headsUpEntry);
+        }
+    }
+
+    @Nullable
+    private HeadsUpEntry getHeadsUpEntryPhone(@NonNull String key) {
+        return mHeadsUpEntryMap.get(key);
+    }
+
+    @Override
+    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+        HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
+        if (headsUpEntry == null) return;
+        if (entry.isRowPinned() || !gutsShown) {
+            headsUpEntry.setGutsShownPinned(gutsShown);
+        }
+    }
+
+    @Override
+    public void extendHeadsUp() {
+        HeadsUpEntry topEntry = getTopHeadsUpEntryPhone();
+        if (topEntry == null) {
+            return;
+        }
+        topEntry.extendPulse();
+    }
+
+    @Nullable
+    private HeadsUpEntry getTopHeadsUpEntryPhone() {
+        if (SceneContainerFlag.isEnabled()) {
+            return (HeadsUpEntry) mTopHeadsUpRow.getValue();
+        } else {
+            return getTopHeadsUpEntry();
+        }
+    }
+
+    @Override
     public boolean isTrackingHeadsUp() {
-        // Might be implemented in subclass.
-        return false;
+        return mTrackingHeadsUp;
     }
 
     /**
@@ -724,11 +1078,23 @@
      */
     @Override
     public boolean canRemoveImmediately(@NonNull String key) {
-        HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
-        if (headsUpEntry != null && headsUpEntry.mUserActionMayIndirectlyRemove) {
+        if (mSwipedOutKeys.contains(key)) {
+            // We always instantly dismiss views being manually swiped out.
+            mSwipedOutKeys.remove(key);
             return true;
         }
-        return headsUpEntry == null || headsUpEntry.wasShownLongEnough()
+
+        HeadsUpEntry headsUpEntry = getHeadsUpEntryPhone(key);
+        HeadsUpEntry topEntry = getTopHeadsUpEntryPhone();
+
+        if (headsUpEntry == null || headsUpEntry != topEntry) {
+            return true;
+        }
+
+        if (headsUpEntry.mUserActionMayIndirectlyRemove) {
+            return true;
+        }
+        return headsUpEntry.wasShownLongEnough()
                 || (headsUpEntry.mEntry != null && headsUpEntry.mEntry.isRowDismissed());
     }
 
@@ -747,7 +1113,13 @@
 
     @NonNull
     protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
-        return new HeadsUpEntry(entry);
+        if (NotificationThrottleHun.isEnabled()) {
+            return new HeadsUpEntry(entry);
+        } else {
+            HeadsUpEntry headsUpEntry = mEntryPool.acquire();
+            headsUpEntry.setEntry(entry);
+            return headsUpEntry;
+        }
     }
 
     /**
@@ -763,12 +1135,79 @@
                 && Notification.CATEGORY_CALL.equals(n.category));
     }
 
+    private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> {
+        if (NotificationThrottleHun.isEnabled()) {
+            mAvalancheController.setEnableAtRuntime(true);
+            if (mEntriesToRemoveWhenReorderingAllowed.isEmpty()) {
+                return;
+            }
+        }
+        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
+        for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
+            if (entry != null && isHeadsUpEntry(entry.getKey())) {
+                // Maybe the heads-up was removed already
+                removeEntry(entry.getKey(), "mOnReorderingAllowedListener");
+            }
+        }
+        mEntriesToRemoveWhenReorderingAllowed.clear();
+        mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
+    };
+
+    private final OnReorderingBannedListener mOnReorderingBannedListener = () -> {
+        if (mAvalancheController != null) {
+            // In open shade the first HUN is pinned, and visual stability logic prevents us from
+            // unpinning this first HUN as long as the shade remains open. AvalancheController only
+            // shows the next HUN when the currently showing HUN is unpinned, so we must disable
+            // throttling here so that the incoming HUN stream is not forever paused. This is reset
+            // when reorder becomes allowed.
+            mAvalancheController.setEnableAtRuntime(false);
+
+            // Note that we cannot do the above when
+            // 1) The remove runnable runs because its delay means it may not run before shade close
+            // 2) Reordering is allowed again (when shade closes) because the HUN appear animation
+            // will have started by then
+        }
+    };
+
+    private final StatusBarStateController.StateListener
+            mStatusBarStateListener = new StatusBarStateController.StateListener() {
+        @Override
+        public void onStateChanged(int newState) {
+            boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+            boolean isKeyguard = newState == StatusBarState.KEYGUARD;
+            mStatusBarState = newState;
+
+            if (wasKeyguard && !isKeyguard && mBypassController.getBypassEnabled()) {
+                ArrayList<String> keysToRemove = new ArrayList<>();
+                for (HeadsUpEntry entry : getHeadsUpEntryList()) {
+                    if (entry.mEntry != null && entry.mEntry.isBubble() && !entry.isSticky()) {
+                        keysToRemove.add(entry.mEntry.getKey());
+                    }
+                }
+                for (String key : keysToRemove) {
+                    removeEntry(key, "mStatusBarStateListener");
+                }
+            }
+        }
+
+        @Override
+        public void onDozingChanged(boolean isDozing) {
+            if (!isDozing) {
+                // Let's make sure all huns we got while dozing time out within the normal timeout
+                // duration. Otherwise they could get stuck for a very long time
+                for (HeadsUpEntry entry : getHeadsUpEntryList()) {
+                    entry.updateEntry(true /* updatePostTime */, "onDozingChanged(false)");
+                }
+            }
+        }
+    };
+
     /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created. This class is public because it is exposed by methods
      * of AvalancheController that take it as param.
      */
-    public class HeadsUpEntry implements Comparable<HeadsUpEntry> {
+    public class HeadsUpEntry implements Comparable<HeadsUpEntry>, HeadsUpRowRepository {
         public boolean mRemoteInputActivatedAtLeastOnce;
         public boolean mRemoteInputActive;
         public boolean mUserActionMayIndirectlyRemove;
@@ -784,6 +1223,14 @@
 
         @Nullable private Runnable mCancelRemoveRunnable;
 
+        private boolean mGutsShownPinned;
+        private final MutableStateFlow<Boolean> mIsPinned = StateFlowKt.MutableStateFlow(false);
+
+        /**
+         * If the time this entry has been on was extended
+         */
+        private boolean extended;
+
         public HeadsUpEntry() {
             NotificationThrottleHun.assertInLegacyMode();
         }
@@ -794,19 +1241,50 @@
             setEntry(entry, createRemoveRunnable(entry));
         }
 
+        @Override
+        @NonNull
+        public String getKey() {
+            return requireEntry().getKey();
+        }
+
+        @Override
+        @NonNull
+        public Object getElementKey() {
+            return requireEntry().getRow();
+        }
+
+        private NotificationEntry requireEntry() {
+            /* check if */ SceneContainerFlag.isUnexpectedlyInLegacyMode();
+            return Objects.requireNonNull(mEntry);
+        }
+
+        @Override
+        @NonNull
+        public StateFlow<Boolean> isPinned() {
+            return mIsPinned;
+        }
+
         /** Attach a NotificationEntry. */
         public void setEntry(@NonNull final NotificationEntry entry) {
             NotificationThrottleHun.assertInLegacyMode();
             setEntry(entry, createRemoveRunnable(entry));
         }
 
-        protected void setEntry(@NonNull final NotificationEntry entry,
+        protected void setEntry(
+                @NonNull final NotificationEntry entry,
                 @Nullable Runnable removeRunnable) {
             mEntry = entry;
             mRemoveRunnable = removeRunnable;
 
             mPostTime = calculatePostTime();
             updateEntry(true /* updatePostTime */, "setEntry");
+
+            if (NotificationThrottleHun.isEnabled()) {
+                mEntriesToRemoveWhenReorderingAllowed.add(entry);
+                if (!mVisualStabilityProvider.isReorderingAllowed()) {
+                    entry.setSeenInShade(true);
+                }
+            }
         }
 
         protected boolean isRowPinned() {
@@ -815,6 +1293,7 @@
 
         protected void setRowPinned(boolean pinned) {
             if (mEntry != null) mEntry.setRowPinned(pinned);
+            mIsPinned.setValue(pinned);
         }
 
         /**
@@ -870,6 +1349,22 @@
 
             // Notify the manager, that the posted time has changed.
             onEntryUpdated(this);
+
+            if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
+                mEntriesToRemoveAfterExpand.remove(mEntry);
+            }
+            if (!NotificationThrottleHun.isEnabled()) {
+                if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
+                    mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
+                }
+            }
+        }
+
+        private void extendPulse() {
+            if (!extended) {
+                extended = true;
+                updateEntry(false, "extendPulse()");
+            }
         }
 
         /**
@@ -878,6 +1373,8 @@
          * @return true if the notification is sticky
          */
         public boolean isSticky() {
+            if (mGutsShownPinned) return true;
+
             if (mEntry == null) return false;
 
             if (ExpandHeadsUpOnInlineReply.isEnabled()) {
@@ -989,7 +1486,29 @@
         }
 
         public void setExpanded(boolean expanded) {
+            if (this.mExpanded == expanded) {
+                return;
+            }
+
             this.mExpanded = expanded;
+            if (expanded) {
+                cancelAutoRemovalCallbacks("setExpanded(true)");
+            } else {
+                updateEntry(false /* updatePostTime */, "setExpanded(false)");
+            }
+        }
+
+        public void setGutsShownPinned(boolean gutsShownPinned) {
+            if (mGutsShownPinned == gutsShownPinned) {
+                return;
+            }
+
+            mGutsShownPinned = gutsShownPinned;
+            if (gutsShownPinned) {
+                cancelAutoRemovalCallbacks("setGutsShownPinned(true)");
+            } else {
+                updateEntry(false /* updatePostTime */, "setGutsShownPinned(false)");
+            }
         }
 
         public void reset() {
@@ -999,6 +1518,8 @@
             mRemoveRunnable = null;
             mExpanded = false;
             mRemoteInputActive = false;
+            mGutsShownPinned = false;
+            extended = false;
         }
 
         /**
@@ -1074,7 +1595,23 @@
 
         /** Creates a runnable to remove this notification from the alerting entries. */
         protected Runnable createRemoveRunnable(NotificationEntry entry) {
-            return () -> removeEntry(entry.getKey(), "createRemoveRunnable");
+            return () -> {
+                if (!NotificationThrottleHun.isEnabled()
+                        && !mVisualStabilityProvider.isReorderingAllowed()
+                        // We don't want to allow reordering while pulsing, but headsup need to
+                        // time out anyway
+                        && !entry.showingPulsing()) {
+                    mEntriesToRemoveWhenReorderingAllowed.add(entry);
+                    mVisualStabilityProvider.addTemporaryReorderingAllowedListener(
+                            mOnReorderingAllowedListener);
+                } else if (mTrackingHeadsUp) {
+                    mEntriesToRemoveAfterExpand.add(entry);
+                    mLogger.logRemoveEntryAfterExpand(entry);
+                } else if (mVisualStabilityProvider.isReorderingAllowed()
+                        || entry.showingPulsing()) {
+                    removeEntry(entry.getKey(), "createRemoveRunnable");
+                }
+            };
         }
 
         /**
@@ -1098,7 +1635,7 @@
                 requestedTimeOutMs = mAvalancheController.getDurationMs(this, mAutoDismissTime);
             }
             final long duration = getRecommendedHeadsUpTimeoutMs(requestedTimeOutMs);
-            return mPostTime + duration;
+            return mPostTime + duration + (extended ? mExtensionTime : 0);
         }
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
index 04fe6b3..b37194b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt
@@ -59,6 +59,7 @@
      * Gets the touchable region needed for heads up notifications. Returns null if no touchable
      * region is required (ie: no heads up notification currently exists).
      */
+    // TODO(b/347007367): With scene container enabled this method may report outdated regions
     fun getTouchableRegion(): Region?
 
     /**
@@ -83,6 +84,10 @@
     /** Returns whether the entry is (pinned and expanded) or (has an active remote input). */
     fun isSticky(key: String?): Boolean
 
+    /**
+     * Returns the value of the tracking-heads-up flag. See the doc of {@code setTrackingHeadsUp} as
+     * well.
+     */
     fun isTrackingHeadsUp(): Boolean
 
     fun onExpandingFinished()
@@ -115,7 +120,7 @@
         key: String,
         releaseImmediately: Boolean,
         animate: Boolean,
-        reason: String
+        reason: String,
     ): Boolean
 
     /** Clears all managed notifications. */
@@ -149,6 +154,10 @@
      */
     fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean)
 
+    /**
+     * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
+     * from the list even after a Heads Up Notification is gone.
+     */
     fun setTrackingHeadsUp(tracking: Boolean)
 
     /** Sets the current user. */
@@ -260,7 +269,7 @@
         key: String,
         releaseImmediately: Boolean,
         animate: Boolean,
-        reason: String
+        reason: String,
     ) = false
 
     override fun setAnimationStateHandler(handler: AnimationStateHandler) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
index abd2453..238e56a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
@@ -28,7 +28,7 @@
     val icon: Icon,
     val text: String,
     val subtext: String,
-    val subtextDescription: String, // version of subtext without "on"/"off" for screen readers
+    val subtextDescription: String, // version of subtext (without "on"/"off") for screen readers
     val enabled: Boolean,
     val stateDescription: String, // "on"/"off" state of the tile, for screen readers
     val onClick: () -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
index 4f595ed..1c13a83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
@@ -23,6 +23,7 @@
 import android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID
 import com.android.settingslib.notification.modes.EnableZenModeDialog
 import com.android.settingslib.notification.modes.ZenMode
+import com.android.settingslib.notification.modes.ZenModeDescriptions
 import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -54,6 +55,7 @@
     private val dialogEventLogger: ModesDialogEventLogger,
 ) {
     private val zenDialogMetricsLogger = QSZenModeDialogMetricsLogger(context)
+    private val zenModeDescriptions = ZenModeDescriptions(context)
 
     // Modes that should be displayed in the dialog
     private val visibleModes: Flow<List<ZenMode>> =
@@ -92,7 +94,8 @@
                         icon = zenModeInteractor.getModeIcon(mode).drawable().asIcon(),
                         text = mode.name,
                         subtext = getTileSubtext(mode),
-                        subtextDescription = getModeDescription(mode) ?: "",
+                        subtextDescription =
+                            getModeDescription(mode, forAccessibility = true) ?: "",
                         enabled = mode.isActive,
                         stateDescription =
                             context.getString(
@@ -145,18 +148,21 @@
      * This description is used directly for the content description of a mode tile for screen
      * readers, and for the tile subtext will be augmented with the current status of the mode.
      */
-    private fun getModeDescription(mode: ZenMode): String? {
+    private fun getModeDescription(mode: ZenMode, forAccessibility: Boolean): String? {
         if (!mode.rule.isEnabled) {
             return context.resources.getString(R.string.zen_mode_set_up)
         }
         if (!mode.rule.isManualInvocationAllowed && !mode.isActive) {
             return context.resources.getString(R.string.zen_mode_no_manual_invocation)
         }
-        return mode.getDynamicDescription(context)
+        return if (forAccessibility)
+            zenModeDescriptions.getTriggerDescriptionForAccessibility(mode)
+                ?: zenModeDescriptions.getTriggerDescription(mode)
+        else zenModeDescriptions.getTriggerDescription(mode)
     }
 
     private fun getTileSubtext(mode: ZenMode): String {
-        val modeDescription = getModeDescription(mode)
+        val modeDescription = getModeDescription(mode, forAccessibility = false)
         return if (mode.isActive) {
             if (modeDescription != null) {
                 context.getString(R.string.zen_mode_on_with_details, modeDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
index 584cd3b..1e043ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt
@@ -36,6 +36,9 @@
     /** Adds the status bar view to the window manager. */
     fun attach()
 
+    /** Called when work should stop and resources should be released. */
+    fun stop()
+
     /** Adds the given view to the status bar window view. */
     fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams)
 
@@ -78,7 +81,7 @@
      */
     fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean)
 
-    interface Factory {
+    fun interface Factory {
         fun create(
             context: Context,
             viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 6953bbf..811a2ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -51,10 +51,12 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.animation.DelegateTransitionAnimatorController;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
+import com.android.systemui.statusbar.core.StatusBarRootModernization;
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
 import com.android.systemui.statusbar.window.StatusBarWindowModule.InternalWindowViewInflater;
@@ -66,6 +68,7 @@
 import dagger.assisted.AssistedInject;
 
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 /**
  * Encapsulates all logic for the status bar window state management.
@@ -79,6 +82,7 @@
     private final StatusBarConfigurationController mStatusBarConfigurationController;
     private final IWindowManager mIWindowManager;
     private final StatusBarContentInsetsProvider mContentInsetsProvider;
+    private final Executor mMainExecutor;
     private int mBarHeight = -1;
     private final State mCurrentState = new State();
     private boolean mIsAttached;
@@ -101,12 +105,14 @@
             IWindowManager iWindowManager,
             @Assisted StatusBarContentInsetsProvider contentInsetsProvider,
             FragmentService fragmentService,
-            Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) {
+            Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
+            @Main Executor mainExecutor) {
         mContext = context;
         mWindowManager = viewCaptureAwareWindowManager;
         mStatusBarConfigurationController = statusBarConfigurationController;
         mIWindowManager = iWindowManager;
         mContentInsetsProvider = contentInsetsProvider;
+        mMainExecutor = mainExecutor;
         mStatusBarWindowView = statusBarWindowViewInflater.inflate(context);
         mFragmentService = fragmentService;
         mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
@@ -167,6 +173,19 @@
     }
 
     @Override
+    public void stop() {
+        StatusBarConnectedDisplays.assertInNewMode();
+
+        mWindowManager.removeView(mStatusBarWindowView);
+
+        if (StatusBarRootModernization.isEnabled()) {
+            return;
+        }
+        // Fragment transactions need to happen on the main thread.
+        mMainExecutor.execute(() -> mFragmentService.removeAndDestroy(mStatusBarWindowView));
+    }
+
+    @Override
     public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) {
         mStatusBarWindowView.addView(view, layoutParams);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 051d463..7403161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -70,6 +70,10 @@
         )
     }
 
+    override suspend fun onDisplayRemovalAction(instance: StatusBarWindowController) {
+        instance.stop()
+    }
+
     override val instanceClass = StatusBarWindowController::class.java
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index d97cae2..d367455 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -50,6 +50,7 @@
 public class SystemUIToast implements ToastPlugin.Toast {
     static final String TAG = "SystemUIToast";
     final Context mContext;
+    final Context mDisplayContext;
     final CharSequence mText;
     final ToastPlugin.Toast mPluginToast;
 
@@ -68,17 +69,18 @@
     @Nullable private final Animator mInAnimator;
     @Nullable private final Animator mOutAnimator;
 
-    SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
-            String packageName, int userId, int orientation) {
-        this(layoutInflater, context, text, null, packageName, userId,
+    SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext,
+            CharSequence text, String packageName, int userId, int orientation) {
+        this(layoutInflater, applicationContext, displayContext, text, null, packageName, userId,
                 orientation);
     }
 
-    SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
-            ToastPlugin.Toast pluginToast, String packageName, @UserIdInt int userId,
-            int orientation) {
+    SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext,
+            CharSequence text, ToastPlugin.Toast pluginToast, String packageName,
+            @UserIdInt int userId, int orientation) {
         mLayoutInflater = layoutInflater;
-        mContext = context;
+        mContext = applicationContext;
+        mDisplayContext = displayContext;
         mText = text;
         mPluginToast = pluginToast;
         mPackageName = packageName;
@@ -221,9 +223,9 @@
             mPluginToast.onOrientationChange(orientation);
         }
 
-        mDefaultY = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
+        mDefaultY = mDisplayContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
         mDefaultGravity =
-                mContext.getResources().getInteger(R.integer.config_toastDefaultGravity);
+                mDisplayContext.getResources().getInteger(R.integer.config_toastDefaultGravity);
     }
 
     private Animator createInAnimator() {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
index 9ae6674..388d4bd 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -65,15 +65,16 @@
     /**
      * Create a toast to be shown by ToastUI.
      */
-    public SystemUIToast createToast(Context context, CharSequence text, String packageName,
-            int userId, int orientation) {
-        LayoutInflater layoutInflater = LayoutInflater.from(context);
+    public SystemUIToast createToast(Context applicationContext, Context displayContext,
+            CharSequence text, String packageName, int userId, int orientation) {
+        LayoutInflater layoutInflater = LayoutInflater.from(displayContext);
         if (isPluginAvailable()) {
-            return new SystemUIToast(layoutInflater, context, text, mPlugin.createToast(text,
-                    packageName, userId), packageName, userId, orientation);
+            return new SystemUIToast(layoutInflater, applicationContext, displayContext, text,
+                    mPlugin.createToast(text, packageName, userId), packageName, userId,
+                    orientation);
         }
-        return new SystemUIToast(layoutInflater, context, text, packageName, userId,
-                orientation);
+        return new SystemUIToast(layoutInflater, applicationContext, displayContext, text,
+                packageName, userId, orientation);
     }
 
     private boolean isPluginAvailable() {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 32a4f12..12f73b8 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -135,8 +135,8 @@
                 return;
             }
             Context displayContext = context.createDisplayContext(display);
-            mToast = mToastFactory.createToast(displayContext /* sysuiContext */, text, packageName,
-                    userHandle.getIdentifier(), mOrientation);
+            mToast = mToastFactory.createToast(mContext, displayContext /* sysuiContext */, text,
+                    packageName, userHandle.getIdentifier(), mOrientation);
 
             if (mToast.getInAnimation() != null) {
                 mToast.getInAnimation().start();
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 3c06828..2a9b1b9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Tracing
 import com.android.systemui.dagger.qualifiers.UiBackground
+import com.android.systemui.util.settings.SettingsSingleThreadBackground
 import dagger.Module
 import dagger.Provides
 import kotlinx.coroutines.CoroutineDispatcher
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
index 49a0f14..af03c52 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/repository/UserAwareSettingsRepository.kt
@@ -85,6 +85,12 @@
         }
     }
 
+    suspend fun setBoolean(name: String, value: Boolean) {
+        withContext(bgContext) {
+            userSettings.putBoolForUser(name, value, userRepository.getSelectedUserInfo().id)
+        }
+    }
+
     suspend fun getString(name: String): String? {
         return withContext(bgContext) {
             userSettings.getStringForUser(name, userRepository.getSelectedUserInfo().id)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
index 6816d35..c4b028d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
@@ -49,7 +49,7 @@
             val drawerContainer = requireViewById<View>(R.id.volume_drawer_container)
             val selectedButtonView =
                 requireViewById<ImageButton>(R.id.volume_new_ringer_active_button)
-            val volumeDialogView = requireViewById<ViewGroup>(R.id.volume_dialog)
+            val volumeDialogBackgroundView = requireViewById<View>(R.id.volume_dialog_background)
             repeatWhenAttached {
                 viewModel(
                     traceName = "VolumeDialogRingerViewBinder",
@@ -71,19 +71,17 @@
                                         is RingerDrawerState.Initial -> {
                                             drawerContainer.visibility = View.GONE
                                             selectedButtonView.visibility = View.VISIBLE
-                                            volumeDialogView.setBackgroundResource(
+                                            volumeDialogBackgroundView.setBackgroundResource(
                                                 R.drawable.volume_dialog_background
                                             )
                                         }
-
                                         is RingerDrawerState.Closed -> {
                                             drawerContainer.visibility = View.GONE
                                             selectedButtonView.visibility = View.VISIBLE
-                                            volumeDialogView.setBackgroundResource(
+                                            volumeDialogBackgroundView.setBackgroundResource(
                                                 R.drawable.volume_dialog_background
                                             )
                                         }
-
                                         is RingerDrawerState.Open -> {
                                             drawerContainer.visibility = View.VISIBLE
                                             selectedButtonView.visibility = View.GONE
@@ -91,17 +89,16 @@
                                                 uiModel.currentButtonIndex !=
                                                     uiModel.availableButtons.size - 1
                                             ) {
-                                                volumeDialogView.setBackgroundResource(
+                                                volumeDialogBackgroundView.setBackgroundResource(
                                                     R.drawable.volume_dialog_background_small_radius
                                                 )
                                             }
                                         }
                                     }
                                 }
-
                                 is RingerViewModelState.Unavailable -> {
                                     drawerAndRingerContainer.visibility = View.GONE
-                                    volumeDialogView.setBackgroundResource(
+                                    volumeDialogBackgroundView.setBackgroundResource(
                                         R.drawable.volume_dialog_background
                                     )
                                 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
index a17c1e5..9078f82 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -38,9 +38,10 @@
 
     fun bind(view: View) {
         with(view) {
-            val volumeDialog: View = requireViewById(R.id.volume_dialog)
             val floatingSlidersContainer: ViewGroup =
                 requireViewById(R.id.volume_dialog_floating_sliders_container)
+            val mainSliderContainer: View =
+                requireViewById(R.id.volume_dialog_main_slider_container)
             repeatWhenAttached {
                 viewModel(
                     traceName = "VolumeDialogSlidersViewBinder",
@@ -49,7 +50,7 @@
                 ) { viewModel ->
                     viewModel.sliders
                         .onEach { uiModel ->
-                            uiModel.sliderComponent.sliderViewBinder().bind(volumeDialog)
+                            uiModel.sliderComponent.sliderViewBinder().bind(mainSliderContainer)
 
                             val floatingSliderViewBinders = uiModel.floatingSliderComponent
                             floatingSlidersContainer.ensureChildCount(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index d9a945c..f6c1743 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -19,13 +19,11 @@
 import android.app.Dialog
 import android.graphics.Rect
 import android.graphics.Region
-import android.view.Gravity
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.InternalInsetsInfo
-import android.widget.FrameLayout
-import androidx.annotation.GravityInt
+import androidx.constraintlayout.motion.widget.MotionLayout
 import com.android.internal.view.RotationPolicy
 import com.android.systemui.lifecycle.WindowLifecycleState
 import com.android.systemui.lifecycle.repeatWhenAttached
@@ -41,7 +39,6 @@
 import com.android.systemui.volume.dialog.ui.VolumeDialogResources
 import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
 import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
-import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
 import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
 import com.android.systemui.volume.dialog.utils.VolumeTracer
 import javax.inject.Inject
@@ -53,6 +50,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.scan
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.suspendCancellableCoroutine
 
@@ -63,7 +61,6 @@
 @Inject
 constructor(
     private val volumeResources: VolumeDialogResources,
-    private val gravityViewModel: VolumeDialogGravityViewModel,
     private val dialogViewModelFactory: VolumeDialogViewModel.Factory,
     private val jankListenerFactory: JankListenerFactory,
     private val tracer: VolumeTracer,
@@ -74,21 +71,23 @@
 
     fun bind(dialog: Dialog) {
         // Root view of the Volume Dialog.
-        val root: ViewGroup = dialog.requireViewById(R.id.volume_dialog_root)
-        // Volume Dialog container view that contains the dialog itself without the floating sliders
-        val container: View = root.requireViewById(R.id.volume_dialog_container)
-        container.alpha = 0f
-        container.repeatWhenAttached {
+        val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root)
+        root.alpha = 0f
+        root.repeatWhenAttached {
             root.viewModel(
                 traceName = "VolumeDialogViewBinder",
                 minWindowLifecycleState = WindowLifecycleState.ATTACHED,
                 factory = { dialogViewModelFactory.create() },
             ) { viewModel ->
-                animateVisibility(container, dialog, viewModel.dialogVisibilityModel)
+                animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
 
                 viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
-                gravityViewModel.dialogGravity
-                    .onEach { container.setLayoutGravity(it) }
+                viewModel.motionState
+                    .scan(0) { acc, motionState ->
+                        // don't animate the initial state
+                        root.transitionToState(motionState, animate = acc != 0)
+                        acc + 1
+                    }
                     .launchIn(this)
 
                 launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
@@ -130,15 +129,13 @@
             .launchIn(this)
     }
 
-    private suspend fun calculateTranslationX(view: View): Float? {
+    private fun calculateTranslationX(view: View): Float? {
         return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) {
-            val dialogGravity = gravityViewModel.dialogGravity.first()
-            val isGravityLeft = (dialogGravity and Gravity.LEFT) == Gravity.LEFT
-            if (isGravityLeft) {
+            if (view.isLayoutRtl) {
                 -1
             } else {
                 1
-            } * view.width / 2.0f
+            } * view.width / 2f
         } else {
             null
         }
@@ -211,10 +208,11 @@
         getBoundsInWindow(boundsRect, false)
     }
 
-    private fun View.setLayoutGravity(@GravityInt newGravity: Int) {
-        val frameLayoutParams =
-            layoutParams as? FrameLayout.LayoutParams
-                ?: error("View must be a child of a FrameLayout")
-        layoutParams = frameLayoutParams.apply { gravity = newGravity }
+    private fun MotionLayout.transitionToState(newState: Int, animate: Boolean) {
+        if (animate) {
+            transitionToState(newState)
+        } else {
+            jumpToState(newState)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
deleted file mode 100644
index 112afb1..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt
+++ /dev/null
@@ -1,93 +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.volume.dialog.ui.viewmodel
-
-import android.content.Context
-import android.content.res.Configuration
-import android.view.Gravity
-import androidx.annotation.GravityInt
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.UiBackground
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.DevicePostureController
-import com.android.systemui.statusbar.policy.devicePosture
-import com.android.systemui.statusbar.policy.onConfigChanged
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
-import javax.inject.Inject
-import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.withContext
-
-/** Exposes dialog [GravityInt] for use in the UI layer. */
-@VolumeDialogScope
-class VolumeDialogGravityViewModel
-@Inject
-constructor(
-    @Application private val context: Context,
-    @VolumeDialog private val coroutineScope: CoroutineScope,
-    @UiBackground private val uiBackgroundCoroutineContext: CoroutineContext,
-    configurationController: ConfigurationController,
-    private val devicePostureController: DevicePostureController,
-) {
-
-    @GravityInt private var originalGravity: Int = context.getAbsoluteGravity()
-
-    val dialogGravity: Flow<Int> =
-        combine(
-                devicePostureController.devicePosture(),
-                configurationController.onConfigChanged.onEach { onConfigurationChanged() },
-            ) { devicePosture, configuration ->
-                context.calculateGravity(devicePosture, configuration)
-            }
-            .stateIn(
-                scope = coroutineScope,
-                started = SharingStarted.Eagerly,
-                context.calculateGravity(),
-            )
-
-    private suspend fun onConfigurationChanged() {
-        withContext(uiBackgroundCoroutineContext) { originalGravity = context.getAbsoluteGravity() }
-    }
-
-    @GravityInt
-    private fun Context.calculateGravity(
-        devicePosture: Int = devicePostureController.devicePosture,
-        config: Configuration = resources.configuration,
-    ): Int {
-        val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE
-        val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
-        val gravity =
-            if (isLandscape && isHalfOpen) {
-                originalGravity or Gravity.TOP
-            } else {
-                originalGravity
-            }
-        return getAbsoluteGravity(gravity)
-    }
-}
-
-@GravityInt
-private fun Context.getAbsoluteGravity(
-    gravity: Int = resources.getInteger(R.integer.volume_dialog_gravity)
-): Int = with(resources) { Gravity.getAbsoluteGravity(gravity, configuration.layoutDirection) }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 869a6a2..0352799 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
@@ -17,7 +17,12 @@
 package com.android.systemui.volume.dialog.ui.viewmodel
 
 import android.content.Context
+import android.content.res.Configuration
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.statusbar.policy.devicePosture
+import com.android.systemui.statusbar.policy.onConfigChanged
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
@@ -32,6 +37,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
 
 /** Provides a state for the Volume Dialog. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -42,8 +48,23 @@
     dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
     volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor,
     volumeDialogStateInteractor: VolumeDialogStateInteractor,
+    devicePostureController: DevicePostureController,
+    configurationController: ConfigurationController,
 ) {
 
+    val motionState: Flow<Int> =
+        combine(
+            devicePostureController.devicePosture(),
+            configurationController.onConfigChanged.onStart {
+                emit(context.resources.configuration)
+            },
+        ) { devicePosture, configuration ->
+            if (shouldOffsetVolumeDialog(devicePosture, configuration)) {
+                R.id.volume_dialog_half_folded_constraint_set
+            } else {
+                R.id.volume_dialog_constraint_set
+            }
+        }
     val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> =
         dialogVisibilityInteractor.dialogVisibility
     val dialogTitle: Flow<String> =
@@ -57,6 +78,13 @@
             }
             .filterNotNull()
 
+    /** @return true when the foldable device screen curve is in the way of the volume dialog */
+    private fun shouldOffsetVolumeDialog(devicePosture: Int, config: Configuration): Boolean {
+        val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE
+        val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+        return isLandscape && isHalfOpen
+    }
+
     @AssistedFactory
     interface Factory {
         fun create(): VolumeDialogViewModel
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 65b6273..2aa6e7b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -105,8 +105,7 @@
 
     private val mainExecutor = ImmediateExecutor()
     private lateinit var repository: FakeKeyguardRepository
-    private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG)
-    private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer)
+    private val clockBuffers = ClockMessageBuffers(LogcatOnlyMessageBuffer(LogLevel.DEBUG))
     private lateinit var underTest: ClockEventController
 
     @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index a940bc9..425aad2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -16,10 +16,12 @@
 import android.view.RemoteAnimationTarget
 import android.view.SurfaceControl
 import android.view.ViewGroup
+import android.view.WindowManager.TRANSIT_NONE
 import android.widget.FrameLayout
 import android.widget.LinearLayout
 import android.window.RemoteTransition
 import android.window.TransitionFilter
+import android.window.WindowAnimationState
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -34,6 +36,10 @@
 import junit.framework.AssertionFailedError
 import kotlin.concurrent.thread
 import kotlin.test.assertEquals
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
 import org.junit.After
 import org.junit.Assert.assertThrows
 import org.junit.Before
@@ -258,7 +264,6 @@
     @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
     @Test
     fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() {
-
         val controller =
             object : DelegateTransitionAnimatorController(controller) {
                 override val transitionCookie =
@@ -273,7 +278,6 @@
     @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
     @Test
     fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() {
-
         // No TransitionCookie
         val controllerWithoutCookie =
             object : DelegateTransitionAnimatorController(controller) {
@@ -348,7 +352,7 @@
     fun doesNotStartIfAnimationIsCancelled() {
         val runner = activityTransitionAnimator.createRunner(controller)
         runner.onAnimationCancelled()
-        runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+        runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback)
 
         waitForIdleSync()
         verify(controller).onTransitionAnimationCancelled()
@@ -361,7 +365,7 @@
     @Test
     fun cancelsIfNoOpeningWindowIsFound() {
         val runner = activityTransitionAnimator.createRunner(controller)
-        runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+        runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback)
 
         waitForIdleSync()
         verify(controller).onTransitionAnimationCancelled()
@@ -374,7 +378,13 @@
     @Test
     fun startsAnimationIfWindowIsOpening() {
         val runner = activityTransitionAnimator.createRunner(controller)
-        runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback)
+        runner.onAnimationStart(
+            TRANSIT_NONE,
+            arrayOf(fakeWindow()),
+            emptyArray(),
+            emptyArray(),
+            iCallback,
+        )
         waitForIdleSync()
         verify(listener).onTransitionAnimationStart()
         verify(controller).onTransitionAnimationStart(anyBoolean())
@@ -387,6 +397,113 @@
         }
     }
 
+    @DisableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
+    @Test
+    fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() {
+        assertThrows(IllegalStateException::class.java) {
+            activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        }
+    }
+
+    @EnableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
+    @Test
+    fun runnerCreatesDelegateLazily_whenPostingTimeouts() {
+        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        assertNull(runner.delegate)
+        runner.postTimeouts()
+        assertNotNull(runner.delegate)
+    }
+
+    @EnableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
+    @Test
+    fun runnerCreatesDelegateLazily_onAnimationStart() {
+        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        assertNull(runner.delegate)
+
+        // The delegate is cleaned up after execution (which happens in another thread), so what we
+        // do instead is check if it becomes non-null at any point with a 1 second timeout. This
+        // will tell us that takeOverWithAnimation() triggered the lazy initialization.
+        var delegateInitialized = false
+        runBlocking {
+            val initChecker = launch {
+                withTimeout(1.seconds) {
+                    while (runner.delegate == null) continue
+                    delegateInitialized = true
+                }
+            }
+            runner.onAnimationStart(
+                TRANSIT_NONE,
+                arrayOf(fakeWindow()),
+                emptyArray(),
+                emptyArray(),
+                iCallback,
+            )
+            initChecker.join()
+        }
+        assertTrue(delegateInitialized)
+    }
+
+    @EnableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
+    @Test
+    fun runnerCreatesDelegateLazily_onAnimationTakeover() {
+        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true)
+        assertNull(runner.delegate)
+
+        // The delegate is cleaned up after execution (which happens in another thread), so what we
+        // do instead is check if it becomes non-null at any point with a 1 second timeout. This
+        // will tell us that takeOverWithAnimation() triggered the lazy initialization.
+        var delegateInitialized = false
+        runBlocking {
+            val initChecker = launch {
+                withTimeout(1.seconds) {
+                    while (runner.delegate == null) continue
+                    delegateInitialized = true
+                }
+            }
+            runner.takeOverAnimation(
+                arrayOf(fakeWindow()),
+                arrayOf(WindowAnimationState()),
+                SurfaceControl.Transaction(),
+                iCallback,
+            )
+            initChecker.join()
+        }
+        assertTrue(delegateInitialized)
+    }
+
+    @DisableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
+    @Test
+    fun animationTakeoverThrows_whenTheFlagsAreDisabled() {
+        val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false)
+        assertThrows(IllegalStateException::class.java) {
+            runner.takeOverAnimation(
+                arrayOf(fakeWindow()),
+                emptyArray(),
+                SurfaceControl.Transaction(),
+                iCallback,
+            )
+        }
+    }
+
+    @DisableFlags(
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+        Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+    )
     @Test
     fun disposeRunner_delegateDereferenced() {
         val runner = activityTransitionAnimator.createRunner(controller)
@@ -409,7 +526,7 @@
             false,
             Rect(),
             Rect(),
-            0,
+            1,
             Point(),
             Rect(),
             bounds,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index 2ff8cbc..5bf1513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -78,8 +78,7 @@
     fun testAvailableMediaDeviceItemFactory_createFromCachedDevice() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
         `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
-        `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
-            .thenReturn(Pair.create(drawable, ""))
+        `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
         val deviceItem = availableMediaDeviceItemFactory.create(context, cachedDevice)
 
         assertDeviceItem(deviceItem, DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
@@ -89,8 +88,7 @@
     fun testConnectedDeviceItemFactory_createFromCachedDevice() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
         `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
-        `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
-            .thenReturn(Pair.create(drawable, ""))
+        `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
         val deviceItem = connectedDeviceItemFactory.create(context, cachedDevice)
 
         assertDeviceItem(deviceItem, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
@@ -100,8 +98,7 @@
     fun testSavedDeviceItemFactory_createFromCachedDevice() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
         `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
-        `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
-            .thenReturn(Pair.create(drawable, ""))
+        `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
         val deviceItem = savedDeviceItemFactory.create(context, cachedDevice)
 
         assertDeviceItem(deviceItem, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
@@ -111,8 +108,7 @@
     @Test
     fun testAvailableAudioSharingMediaDeviceItemFactory_createFromCachedDevice() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
-        `when`(BluetoothUtils.getBtClassDrawableWithDescription(any(), any()))
-            .thenReturn(Pair.create(drawable, ""))
+        `when`(cachedDevice.drawableWithDescription).thenReturn(Pair.create(drawable, ""))
         val deviceItem =
             AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager)
                 .create(context, cachedDevice)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt
new file mode 100644
index 0000000..8d9fa6a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderContentProviderTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.graphics
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.Context
+import android.database.Cursor
+import android.net.Uri
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.provider.ProviderTestRule
+import com.android.systemui.SysuiTestCase
+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.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+const val AUTHORITY = "exception.provider.authority"
+val TEST_URI = Uri.Builder().scheme("content").authority(AUTHORITY).path("path").build()
+
+@SmallTest
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class ImageLoaderContentProviderTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val mockContext = mock<Context>()
+    private lateinit var imageLoader: ImageLoader
+
+    @Rule
+    @JvmField
+    @Suppress("DEPRECATION")
+    public val providerTestRule =
+        ProviderTestRule.Builder(ExceptionThrowingContentProvider::class.java, AUTHORITY).build()
+
+    @Before
+    fun setUp() {
+        whenever(mockContext.contentResolver).thenReturn(providerTestRule.resolver)
+        imageLoader = ImageLoader(mockContext, kosmos.testDispatcher)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun loadFromTestContentProvider_throwsException() {
+        // This checks if the resolution actually throws the exception from test provider.
+        mockContext.contentResolver.query(TEST_URI, null, null, null)
+    }
+
+    @Test
+    fun loadFromRuntimeExceptionThrowingProvider_returnsNull() =
+        testScope.runTest { assertThat(imageLoader.loadBitmap(ImageLoader.Uri(TEST_URI))).isNull() }
+}
+
+class ExceptionThrowingContentProvider : ContentProvider() {
+    override fun query(
+        uri: Uri,
+        projection: Array<out String>?,
+        selection: String?,
+        selectionArgs: Array<out String>?,
+        sortOrder: String?,
+    ): Cursor? {
+        throw IllegalArgumentException("Test exception")
+    }
+
+    override fun getType(uri: Uri): String? {
+        throw IllegalArgumentException("Test exception")
+    }
+
+    override fun insert(uri: Uri, values: ContentValues?): Uri? {
+        throw IllegalArgumentException("Test exception")
+    }
+
+    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+        throw IllegalArgumentException("Test exception")
+    }
+
+    override fun update(
+        uri: Uri,
+        values: ContentValues?,
+        selection: String?,
+        selectionArgs: Array<out String>?,
+    ): Int {
+        throw IllegalArgumentException("Test exception")
+    }
+
+    override fun onCreate(): Boolean = true
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
new file mode 100644
index 0000000..f8d8481
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.ui.viewmodel
+
+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.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
+import com.android.systemui.keyboard.shortcut.shortcutCustomizationViewModelFactory
+import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutCustomizationViewModelTest : SysuiTestCase() {
+
+    private val kosmos = Kosmos()
+    private val testScope = kosmos.testScope
+    private val viewModel = kosmos.shortcutCustomizationViewModelFactory.create()
+
+    @Test
+    fun uiState_inactiveByDefault() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    @Test
+    fun uiState_correctlyUpdatedWhenAddShortcutCustomizationIsRequested() {
+        testScope.runTest {
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+
+            assertThat(uiState).isEqualTo(expectedStandardAddShortcutUiState)
+        }
+    }
+
+    @Test
+    fun uiState_consumedOnAddDialogShown() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onAddShortcutDialogShown()
+
+            assertThat((uiState as ShortcutCustomizationUiState.AddShortcutDialog).isDialogShowing)
+                .isTrue()
+        }
+    }
+
+    @Test
+    fun uiState_inactiveAfterDialogIsDismissed() {
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+            viewModel.onAddShortcutDialogShown()
+            viewModel.onAddShortcutDialogDismissed()
+            assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
+        }
+    }
+
+    private val standardAddShortcutRequest =
+        ShortcutCustomizationRequestInfo.Add(
+            label = "Standard shortcut",
+            categoryType = ShortcutCategoryType.System,
+            subCategoryLabel = "Standard subcategory",
+        )
+
+    private val expectedStandardAddShortcutUiState =
+        ShortcutCustomizationUiState.AddShortcutDialog(
+            shortcutLabel = "Standard shortcut",
+            shouldShowErrorMessage = false,
+            isValidKeyCombination = false,
+            defaultCustomShortcutModifierKey =
+                ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+            isDialogShowing = false,
+        )
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index e1845a1..7e85dd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -213,7 +213,7 @@
             )
         val keyguardTouchHandlingInteractor =
             KeyguardTouchHandlingInteractor(
-                appContext = mContext,
+                context = mContext,
                 scope = testScope.backgroundScope,
                 transitionInteractor = kosmos.keyguardTransitionInteractor,
                 repository = repository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
index 0b9c06f..5ada2f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
@@ -222,7 +222,7 @@
         when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(SUB_ID);
         SubscriptionInfo info = mock(SubscriptionInfo.class);
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info);
-        when(mToastFactory.createToast(any(), anyString(), anyString(), anyInt(), anyInt()))
+        when(mToastFactory.createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt()))
             .thenReturn(mSystemUIToast);
         when(mSystemUIToast.getView()).thenReturn(mToastView);
         when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS);
@@ -275,8 +275,8 @@
         mInternetDialogController.connectCarrierNetwork();
 
         verify(mMergedCarrierEntry).connect(null /* callback */, false /* showToast */);
-        verify(mToastFactory).createToast(any(), eq(TOAST_MESSAGE_STRING), anyString(), anyInt(),
-            anyInt());
+        verify(mToastFactory).createToast(any(), any(), eq(TOAST_MESSAGE_STRING), anyString(),
+                anyInt(), anyInt());
     }
 
     @Test
@@ -288,7 +288,7 @@
         mInternetDialogController.connectCarrierNetwork();
 
         verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
-        verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+        verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
             anyInt());
     }
 
@@ -302,7 +302,7 @@
         mInternetDialogController.connectCarrierNetwork();
 
         verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
-        verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+        verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
             anyInt());
     }
 
@@ -321,7 +321,7 @@
         mInternetDialogController.connectCarrierNetwork();
 
         verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
-        verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(),
+        verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
             anyInt());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
index 8bd8b72..2812bd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt
@@ -15,11 +15,16 @@
  */
 package systemui.shared.clocks.view
 
+import android.graphics.Typeface
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.clocks.ClockMessageBuffers
+import com.android.systemui.plugins.clocks.ClockSettings
+import com.android.systemui.shared.clocks.ClockContext
 import com.android.systemui.shared.clocks.FontTextStyle
 import com.android.systemui.shared.clocks.LogUtil
+import com.android.systemui.shared.clocks.TypefaceCache
 import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
 import org.junit.Assert.assertEquals
 import org.junit.Before
@@ -38,7 +43,23 @@
 
     @Before
     fun setup() {
-        underTest = SimpleDigitalClockTextView(context, messageBuffer)
+        underTest =
+            SimpleDigitalClockTextView(
+                ClockContext(
+                    context,
+                    context.resources,
+                    ClockSettings(),
+                    TypefaceCache(messageBuffer) {
+                        // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
+                        return@TypefaceCache Typeface.create(
+                            "google-sans-flex-clock",
+                            Typeface.NORMAL,
+                        )
+                    },
+                    ClockMessageBuffers(messageBuffer),
+                    messageBuffer,
+                )
+            )
         underTest.textStyle = FontTextStyle()
         underTest.aodStyle = FontTextStyle()
         underTest.text = "0"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index a8618eb..3a46d03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -20,9 +20,8 @@
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
 import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -31,7 +30,6 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.statusbar.policy.configurationController
 import com.android.systemui.statusbar.policy.fakeConfigurationController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
@@ -144,7 +142,7 @@
                         context = context,
                         configurationController = configurationController,
                         dumpManager = mock(),
-                        splitShadeStateController = ResourcesSplitShadeStateController()
+                        splitShadeStateController = ResourcesSplitShadeStateController(),
                     ),
                 keyguardTransitionControllerFactory = { notificationPanelController ->
                     LockscreenShadeKeyguardTransitionController(
@@ -153,7 +151,7 @@
                         context = context,
                         configurationController = configurationController,
                         dumpManager = mock(),
-                        splitShadeStateController = ResourcesSplitShadeStateController()
+                        splitShadeStateController = ResourcesSplitShadeStateController(),
                     )
                 },
                 depthController = depthController,
@@ -171,7 +169,7 @@
                 splitShadeStateController = ResourcesSplitShadeStateController(),
                 shadeLockscreenInteractorLazy = { shadeLockscreenInteractor },
                 naturalScrollingSettingObserver = naturalScrollingSettingObserver,
-                lazyQSSceneAdapter = { qsSceneAdapter }
+                lazyQSSceneAdapter = { qsSceneAdapter },
             )
 
         transitionController.addCallback(transitionControllerCallback)
@@ -229,7 +227,7 @@
             verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED)
             assertFalse(
                 "Waking to shade locked when not dozing",
-                transitionController.isWakingToShadeLocked
+                transitionController.isWakingToShadeLocked,
             )
         }
 
@@ -247,9 +245,7 @@
     fun testDontGoWhenShadeDisabled() =
         testScope.runTest {
             disableFlagsRepository.disableFlags.value =
-                DisableFlagsModel(
-                    disable2 = DISABLE2_NOTIFICATION_SHADE,
-                )
+                DisableFlagsModel(disable2 = DISABLE2_NOTIFICATION_SHADE)
             testScope.runCurrent()
             transitionController.goToLockedShade(null)
             verify(statusbarStateController, never()).setState(anyInt())
@@ -454,7 +450,7 @@
             val distance = 10
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_scrim_transition_distance,
-                distance
+                distance,
             )
             configurationController.notifyConfigurationChanged()
 
@@ -463,7 +459,7 @@
             verify(scrimController)
                 .transitionToFullShadeProgress(
                     progress = eq(0.5f),
-                    lockScreenNotificationsProgress = anyFloat()
+                    lockScreenNotificationsProgress = anyFloat(),
                 )
         }
 
@@ -474,11 +470,11 @@
             val delay = 10
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
-                distance
+                distance,
             )
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
-                delay
+                delay,
             )
             configurationController.notifyConfigurationChanged()
 
@@ -487,7 +483,7 @@
             verify(scrimController)
                 .transitionToFullShadeProgress(
                     progress = anyFloat(),
-                    lockScreenNotificationsProgress = eq(0.1f)
+                    lockScreenNotificationsProgress = eq(0.1f),
                 )
         }
 
@@ -498,11 +494,11 @@
             val delay = 50
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
-                distance
+                distance,
             )
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
-                delay
+                delay,
             )
             configurationController.notifyConfigurationChanged()
 
@@ -511,7 +507,7 @@
             verify(scrimController)
                 .transitionToFullShadeProgress(
                     progress = anyFloat(),
-                    lockScreenNotificationsProgress = eq(0f)
+                    lockScreenNotificationsProgress = eq(0f),
                 )
         }
 
@@ -522,11 +518,11 @@
             val delay = 50
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_distance,
-                distance
+                distance,
             )
             context.orCreateTestableResources.addOverride(
                 R.dimen.lockscreen_shade_notifications_scrim_transition_delay,
-                delay
+                delay,
             )
             configurationController.notifyConfigurationChanged()
 
@@ -535,7 +531,7 @@
             verify(scrimController)
                 .transitionToFullShadeProgress(
                     progress = anyFloat(),
-                    lockScreenNotificationsProgress = eq(1f)
+                    lockScreenNotificationsProgress = eq(1f),
                 )
         }
 
@@ -627,7 +623,7 @@
      */
     private fun ScrimController.transitionToFullShadeProgress(
         progress: Float,
-        lockScreenNotificationsProgress: Float
+        lockScreenNotificationsProgress: Float,
     ) {
         setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
index e72109d..a3c5181 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
@@ -27,16 +27,15 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
 import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController
-import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations.initMocks
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -47,14 +46,13 @@
 
     private lateinit var entry: NotificationEntry
 
-    @Mock private lateinit var pipeline: NotifPipeline
-    @Mock private lateinit var notifLiveDataStoreImpl: NotifLiveDataStoreImpl
-    @Mock private lateinit var stackController: NotifStackController
-    @Mock private lateinit var section: NotifSection
+    private val pipeline: NotifPipeline = mock()
+    private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl = mock()
+    private val stackController: NotifStackController = mock()
+    private val section: NotifSection = mock()
 
     @Before
     fun setUp() {
-        initMocks(this)
         entry = NotificationEntryBuilder().setSection(section).build()
         coordinator = DataStoreCoordinator(notifLiveDataStoreImpl)
         coordinator.attach(pipeline)
@@ -76,31 +74,35 @@
             listOf(
                 notificationEntry("foo", 1),
                 notificationEntry("foo", 2),
-                GroupEntryBuilder().setSummary(
-                    notificationEntry("bar", 1)
-                ).setChildren(
-                    listOf(
-                        notificationEntry("bar", 2),
-                        notificationEntry("bar", 3),
-                        notificationEntry("bar", 4)
+                GroupEntryBuilder()
+                    .setSummary(notificationEntry("bar", 1))
+                    .setChildren(
+                        listOf(
+                            notificationEntry("bar", 2),
+                            notificationEntry("bar", 3),
+                            notificationEntry("bar", 4),
+                        )
                     )
-                ).setSection(section).build(),
-                notificationEntry("baz", 1)
+                    .setSection(section)
+                    .build(),
+                notificationEntry("baz", 1),
             ),
-            stackController
+            stackController,
         )
         val list: List<NotificationEntry> = withArgCaptor {
             verify(notifLiveDataStoreImpl).setActiveNotifList(capture())
         }
-        assertThat(list.map { it.key }).containsExactly(
-            "0|foo|1|null|0",
-            "0|foo|2|null|0",
-            "0|bar|1|null|0",
-            "0|bar|2|null|0",
-            "0|bar|3|null|0",
-            "0|bar|4|null|0",
-            "0|baz|1|null|0"
-        ).inOrder()
+        assertThat(list.map { it.key })
+            .containsExactly(
+                "0|foo|1|null|0",
+                "0|foo|2|null|0",
+                "0|bar|1|null|0",
+                "0|bar|2|null|0",
+                "0|bar|3|null|0",
+                "0|bar|4|null|0",
+                "0|baz|1|null|0",
+            )
+            .inOrder()
         verifyNoMoreInteractions(notifLiveDataStoreImpl)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index 56b70bd..2c37f51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -38,41 +38,37 @@
 import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
 import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.withArgCaptor
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.Mockito.`when` as whenever
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class StackCoordinatorTest : SysuiTestCase() {
+    private lateinit var entry: NotificationEntry
     private lateinit var coordinator: StackCoordinator
     private lateinit var afterRenderListListener: OnAfterRenderListListener
 
-    private lateinit var entry: NotificationEntry
-
-    @Mock private lateinit var pipeline: NotifPipeline
-    @Mock private lateinit var groupExpansionManagerImpl: GroupExpansionManagerImpl
-    @Mock private lateinit var renderListInteractor: RenderNotificationListInteractor
-    @Mock private lateinit var activeNotificationsInteractor: ActiveNotificationsInteractor
-    @Mock
-    private lateinit var sensitiveNotificationProtectionController:
-        SensitiveNotificationProtectionController
-    @Mock private lateinit var stackController: NotifStackController
-    @Mock private lateinit var section: NotifSection
-    @Mock private lateinit var row: ExpandableNotificationRow
+    private val pipeline: NotifPipeline = mock()
+    private val groupExpansionManagerImpl: GroupExpansionManagerImpl = mock()
+    private val renderListInteractor: RenderNotificationListInteractor = mock()
+    private val activeNotificationsInteractor: ActiveNotificationsInteractor = mock()
+    private val sensitiveNotificationProtectionController:
+        SensitiveNotificationProtectionController =
+        mock()
+    private val stackController: NotifStackController = mock()
+    private val section: NotifSection = mock()
+    private val row: ExpandableNotificationRow = mock()
 
     @Before
     fun setUp() {
-        initMocks(this)
-
         whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(false)
 
         entry = NotificationEntryBuilder().setSection(section).build()
@@ -86,9 +82,9 @@
                 sensitiveNotificationProtectionController,
             )
         coordinator.attach(pipeline)
-        afterRenderListListener = withArgCaptor {
-            verify(pipeline).addOnAfterRenderListListener(capture())
-        }
+        val captor = argumentCaptor<OnAfterRenderListListener>()
+        verify(pipeline).addOnAfterRenderListListener(captor.capture())
+        afterRenderListListener = captor.lastValue
     }
 
     @Test
@@ -109,7 +105,16 @@
     fun testSetNotificationStats_clearableAlerting() {
         whenever(section.bucket).thenReturn(BUCKET_ALERTING)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
-        verify(stackController).setNotifStats(NotifStats(1, false, true, false, false))
+        verify(stackController)
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = true,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(activeNotificationsInteractor)
     }
 
@@ -120,7 +125,16 @@
         whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
         whenever(section.bucket).thenReturn(BUCKET_ALERTING)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
-        verify(stackController).setNotifStats(NotifStats(1, true, false, false, false))
+        verify(stackController)
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = true,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(activeNotificationsInteractor)
     }
 
@@ -129,7 +143,16 @@
     fun testSetNotificationStats_clearableSilent() {
         whenever(section.bucket).thenReturn(BUCKET_SILENT)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
-        verify(stackController).setNotifStats(NotifStats(1, false, false, false, true))
+        verify(stackController)
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = true,
+                )
+            )
         verifyNoMoreInteractions(activeNotificationsInteractor)
     }
 
@@ -140,7 +163,16 @@
         whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
         whenever(section.bucket).thenReturn(BUCKET_SILENT)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
-        verify(stackController).setNotifStats(NotifStats(1, false, false, true, false))
+        verify(stackController)
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = true,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(activeNotificationsInteractor)
     }
 
@@ -150,7 +182,15 @@
         whenever(section.bucket).thenReturn(BUCKET_ALERTING)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(activeNotificationsInteractor)
-            .setNotifStats(NotifStats(1, false, true, false, false))
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = true,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(stackController)
     }
 
@@ -158,14 +198,22 @@
     @EnableFlags(
         FooterViewRefactor.FLAG_NAME,
         FLAG_SCREENSHARE_NOTIFICATION_HIDING,
-        FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
+        FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX,
     )
     fun testSetNotificationStats_footerFlagOn_isSensitiveStateActive_nonClearableAlerting() {
         whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
         whenever(section.bucket).thenReturn(BUCKET_ALERTING)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(activeNotificationsInteractor)
-            .setNotifStats(NotifStats(1, true, false, false, false))
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = true,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(stackController)
     }
 
@@ -175,7 +223,15 @@
         whenever(section.bucket).thenReturn(BUCKET_SILENT)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(activeNotificationsInteractor)
-            .setNotifStats(NotifStats(1, false, false, false, true))
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = true,
+                )
+            )
         verifyNoMoreInteractions(stackController)
     }
 
@@ -183,27 +239,41 @@
     @EnableFlags(
         FooterViewRefactor.FLAG_NAME,
         FLAG_SCREENSHARE_NOTIFICATION_HIDING,
-        FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
+        FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX,
     )
     fun testSetNotificationStats_footerFlagOn_isSensitiveStateActive_nonClearableSilent() {
         whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)
         whenever(section.bucket).thenReturn(BUCKET_SILENT)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(activeNotificationsInteractor)
-            .setNotifStats(NotifStats(1, false, false, true, false))
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = false,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = true,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(stackController)
     }
 
     @Test
-    @EnableFlags(
-        FooterViewRefactor.FLAG_NAME
-    )
+    @EnableFlags(FooterViewRefactor.FLAG_NAME)
     fun testSetNotificationStats_footerFlagOn_nonClearableRedacted() {
         entry.setSensitive(true, true)
         whenever(section.bucket).thenReturn(BUCKET_ALERTING)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(activeNotificationsInteractor)
-            .setNotifStats(NotifStats(1, hasNonClearableAlertingNotifs = true, false, false, false))
+            .setNotifStats(
+                NotifStats(
+                    1,
+                    hasNonClearableAlertingNotifs = true,
+                    hasClearableAlertingNotifs = false,
+                    hasNonClearableSilentNotifs = false,
+                    hasClearableSilentNotifs = false,
+                )
+            )
         verifyNoMoreInteractions(stackController)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
index 0c0b5ba..a2fabf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/data/repository/KeyguardBypassRepositoryTest.kt
@@ -34,45 +34,27 @@
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
 import com.android.systemui.statusbar.policy.devicePostureController
 import com.android.systemui.testKosmos
-import com.android.systemui.tuner.TunerService
-import com.android.systemui.tuner.tunerService
-import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @EnableSceneContainer
 class KeyguardBypassRepositoryTest : SysuiTestCase() {
-    @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
 
-    private lateinit var tunableCallback: TunerService.Tunable
     private lateinit var postureControllerCallback: DevicePostureController.Callback
 
     private val kosmos = testKosmos()
     private lateinit var underTest: KeyguardBypassRepository
     private val testScope = kosmos.testScope
 
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-    }
-
     // overrideFaceBypassSetting overridden to true
     // isFaceEnrolledAndEnabled true
     // isPostureAllowedForFaceAuth true/false on posture changes
@@ -148,24 +130,25 @@
             val bypassEnabled by collectLastValue(underTest.isBypassAvailable)
             runCurrent()
             postureControllerCallback = kosmos.devicePostureController.verifyCallback()
-            tunableCallback = kosmos.tunerService.captureCallback()
 
             // Update face auth posture to match config
             postureControllerCallback.onPostureChanged(DEVICE_POSTURE_CLOSED)
 
             // FACE_UNLOCK_DISMISSES_KEYGUARD setting true
-            whenever(kosmos.tunerService.getValue(eq(faceUnlockDismissesKeyguard), anyInt()))
-                .thenReturn(1)
-            tunableCallback.onTuningChanged(faceUnlockDismissesKeyguard, "")
+            kosmos.userAwareSecureSettingsRepository.setBoolean(
+                Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+                true,
+            )
 
             runCurrent()
             // Assert bypass enabled
             assertThat(bypassEnabled).isTrue()
 
             // FACE_UNLOCK_DISMISSES_KEYGUARD setting false
-            whenever(kosmos.tunerService.getValue(eq(faceUnlockDismissesKeyguard), anyInt()))
-                .thenReturn(0)
-            tunableCallback.onTuningChanged(faceUnlockDismissesKeyguard, "")
+            kosmos.userAwareSecureSettingsRepository.setBoolean(
+                Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
+                false,
+            )
 
             runCurrent()
             // Assert bypass not enabled
@@ -229,10 +212,3 @@
         private const val FACE_UNLOCK_BYPASS_NEVER = 2
     }
 }
-
-private const val faceUnlockDismissesKeyguard = Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD
-
-private fun TunerService.captureCallback() =
-    withArgCaptor<TunerService.Tunable> {
-        verify(this@captureCallback).addTunable(capture(), eq(faceUnlockDismissesKeyguard))
-    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
index 92dc897..7fd9276 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayWindowPropertiesRepository.kt
@@ -35,4 +35,9 @@
                 )
                 .also { properties.put(displayId, windowType, it) }
     }
+
+    /** Sets an instance, just for testing purposes. */
+    fun insert(instance: DisplayWindowProperties) {
+        properties.put(instance.displayId, instance.windowType, instance)
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
new file mode 100644
index 0000000..b24b3ad
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.ui.viewmodel
+
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+
+val Kosmos.dreamUserActionsViewModel by
+    Kosmos.Fixture {
+        DreamUserActionsViewModel(
+            deviceUnlockedInteractor = deviceUnlockedInteractor,
+            shadeInteractor = shadeInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index 32469b6..ad38bbe 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -23,13 +23,13 @@
 
 class FakeFeatureFlagsClassic : FakeFeatureFlags()
 
+val FeatureFlagsClassic.fake
+    get() = this as FakeFeatureFlagsClassic
+
 @Deprecated(
     message = "Use FakeFeatureFlagsClassic instead.",
     replaceWith =
-        ReplaceWith(
-            "FakeFeatureFlagsClassic",
-            "com.android.systemui.flags.FakeFeatureFlagsClassic",
-        ),
+        ReplaceWith("FakeFeatureFlagsClassic", "com.android.systemui.flags.FakeFeatureFlagsClassic"),
 )
 open class FakeFeatureFlags : FeatureFlagsClassic {
     private val booleanFlags = mutableMapOf<String, Boolean>()
@@ -105,6 +105,7 @@
                 listener.onFlagChanged(
                     object : FlagListenable.FlagEvent {
                         override val flagName = flag.name
+
                         override fun requestNoRestart() {}
                     }
                 )
@@ -165,7 +166,7 @@
 
 @Module(includes = [FakeFeatureFlagsClassicModule.Bindings::class])
 class FakeFeatureFlagsClassicModule(
-    @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(),
+    @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
 ) {
 
     constructor(
@@ -175,7 +176,9 @@
     @Module
     interface Bindings {
         @Binds fun bindFake(fake: FakeFeatureFlagsClassic): FeatureFlagsClassic
+
         @Binds fun bindClassic(classic: FeatureFlagsClassic): FeatureFlags
+
         @Binds fun bindFakeClassic(fake: FakeFeatureFlagsClassic): FakeFeatureFlags
     }
 }
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 f52f039..903bc8e 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
@@ -109,6 +109,7 @@
             applicationCoroutineScope,
             testDispatcher,
             shortcutCategoriesUtils,
+            applicationContext,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
index c91823c..0de456b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBypassRepositoryKosmos.kt
@@ -25,8 +25,8 @@
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
-import com.android.systemui.tuner.tunerService
 import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
@@ -37,7 +37,7 @@
         biometricSettingsRepository,
         devicePostureRepository,
         dumpManager,
-        tunerService,
+        userAwareSecureSettingsRepository,
         testDispatcher,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
index 769612c..255a780 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorKosmos.kt
@@ -30,7 +30,7 @@
 val Kosmos.keyguardTouchHandlingInteractor by
     Kosmos.Fixture {
         KeyguardTouchHandlingInteractor(
-            appContext = applicationContext,
+            context = applicationContext,
             scope = applicationCoroutineScope,
             transitionInteractor = keyguardTransitionInteractor,
             repository = keyguardRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 63e6eb6..3d60abf 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -71,14 +71,19 @@
 import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
+import com.android.systemui.statusbar.phone.keyguardBypassController
 import com.android.systemui.statusbar.phone.scrimController
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor
+import com.android.systemui.statusbar.policy.configurationController
 import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
 import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
 import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel
@@ -105,6 +110,7 @@
     val testScope by lazy { kosmos.testScope }
     val fakeExecutor by lazy { kosmos.fakeExecutor }
     val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }
+    val configurationController by lazy { kosmos.configurationController }
     val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
     val configurationInteractor by lazy { kosmos.configurationInteractor }
     val bouncerRepository by lazy { kosmos.bouncerRepository }
@@ -115,13 +121,14 @@
     val seenNotificationsInteractor by lazy { kosmos.seenNotificationsInteractor }
     val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
     val keyguardBouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
+    val keyguardBypassController by lazy { kosmos.keyguardBypassController }
     val keyguardInteractor by lazy { kosmos.keyguardInteractor }
     val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
     val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
     val keyguardStatusBarViewModel by lazy { kosmos.keyguardStatusBarViewModel }
     val powerRepository by lazy { kosmos.fakePowerRepository }
     val clock by lazy { kosmos.systemClock }
-    val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
+    val mobileConnectionsRepository by lazy { kosmos.mobileConnectionsRepository }
     val simBouncerInteractor by lazy { kosmos.simBouncerInteractor }
     val statusBarStateController by lazy { kosmos.statusBarStateController }
     val statusBarModePerDisplayRepository by lazy { kosmos.fakeStatusBarModePerDisplayRepository }
@@ -158,6 +165,7 @@
     val shadeRepository by lazy { kosmos.shadeRepository }
     val shadeInteractor by lazy { kosmos.shadeInteractor }
     val notificationShadeWindowModel by lazy { kosmos.notificationShadeWindowModel }
+    val visualStabilityProvider by lazy { kosmos.visualStabilityProvider }
     val wifiInteractor by lazy { kosmos.wifiInteractor }
     val fakeWifiRepository by lazy { kosmos.fakeWifiRepository }
     val volumeDialogInteractor by lazy { kosmos.volumeDialogInteractor }
@@ -177,4 +185,6 @@
     val lockscreenToGlanceableHubTransitionViewModel by lazy {
         kosmos.lockscreenToGlanceableHubTransitionViewModel
     }
+    val disableFlagsInteractor by lazy { kosmos.disableFlagsInteractor }
+    val fakeDisableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
index 4ed49123..45d5b38 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt
@@ -33,7 +33,7 @@
 import com.android.systemui.qs.ui.viewmodel.quickSettingsContainerViewModelFactory
 import com.android.systemui.shade.largeScreenHeaderHelper
 import com.android.systemui.shade.transition.largeScreenShadeInterpolator
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
 import com.android.systemui.statusbar.sysuiStatusBarStateController
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -51,7 +51,7 @@
                     footerActionsController,
                     sysuiStatusBarStateController,
                     deviceEntryInteractor,
-                    disableFlagsRepository,
+                    disableFlagsInteractor,
                     keyguardTransitionInteractor,
                     largeScreenShadeInterpolator,
                     configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
index 8b12425..a4a63ec 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -21,6 +21,7 @@
 import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.scene.shared.model.SceneFamilies
@@ -34,6 +35,7 @@
         HomeSceneFamilyResolver(
             applicationScope = applicationCoroutineScope,
             deviceEntryInteractor = deviceEntryInteractor,
+            keyguardInteractor = keyguardInteractor,
             keyguardEnabledInteractor = keyguardEnabledInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 39f58ae..af6d624 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.shade.ShadeModule
 import com.android.systemui.shade.data.repository.shadeRepository
-import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
 import com.android.systemui.statusbar.phone.dozeParameters
 import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
 import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
@@ -60,7 +60,7 @@
         ShadeInteractorImpl(
             scope = applicationCoroutineScope,
             deviceProvisioningInteractor = deviceProvisioningInteractor,
-            disableFlagsRepository = disableFlagsRepository,
+            disableFlagsInteractor = disableFlagsInteractor,
             dozeParams = dozeParameters,
             keyguardRepository = fakeKeyguardRepository,
             keyguardTransitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
index 466a3eb..9dbb547 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
@@ -15,7 +15,7 @@
 package com.android.systemui.statusbar.disableflags.data.repository
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel
 import dagger.Binds
 import dagger.Module
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
index e4ccc2c..7b4b047 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutInfo.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyboard.shortcut.shared.model
+package com.android.systemui.statusbar.disableflags.domain.interactor
 
-data class ShortcutInfo(
-    val label: String,
-    val categoryType: ShortcutCategoryType,
-    val subCategoryLabel: String,
-)
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
+
+val Kosmos.disableFlagsInteractor by Fixture {
+    DisableFlagsInteractor(repository = disableFlagsRepository)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
index d76defe..99ed4f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt
@@ -18,7 +18,7 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 
 val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by
@@ -26,6 +26,6 @@
         AirplaneModeInteractor(
             FakeAirplaneModeRepository(),
             FakeConnectivityRepository(),
-            fakeMobileConnectionsRepository,
+            mobileConnectionsRepository,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index de73d33..bfd46b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -77,11 +77,7 @@
 
     override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
         return subIdRepos[subId]
-            ?: FakeMobileConnectionRepository(
-                    subId,
-                    tableLogBuffer,
-                )
-                .also { subIdRepos[subId] = it }
+            ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
     }
 
     override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
@@ -135,3 +131,6 @@
         const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
     }
 }
+
+val MobileConnectionsRepository.fake
+    get() = this as FakeMobileConnectionsRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
index cd22f1d..b952d71 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt
@@ -19,12 +19,20 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+
+val Kosmos.mobileMappingsProxy: MobileMappingsProxy by Fixture { FakeMobileMappingsProxy() }
+
+var Kosmos.mobileConnectionsRepositoryLogbufferName by Fixture { "FakeMobileConnectionsRepository" }
 
 val Kosmos.fakeMobileConnectionsRepository by Fixture {
     FakeMobileConnectionsRepository(
-        tableLogBuffer = logcatTableLogBuffer(this, "FakeMobileConnectionsRepository"),
+        mobileMappings = mobileMappingsProxy,
+        tableLogBuffer = logcatTableLogBuffer(this, mobileConnectionsRepositoryLogbufferName),
     )
 }
 
-val Kosmos.mobileConnectionsRepository by
-    Fixture<MobileConnectionsRepository> { fakeMobileConnectionsRepository }
+val Kosmos.mobileConnectionsRepository: MobileConnectionsRepository by Fixture {
+    fakeMobileConnectionsRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
index 8e656cf..00bfa99 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
@@ -18,7 +18,5 @@
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.fakeConnectivityRepository: FakeConnectivityRepository by
-    Kosmos.Fixture { FakeConnectivityRepository() }
 val Kosmos.connectivityRepository: ConnectivityRepository by
-    Kosmos.Fixture { fakeConnectivityRepository }
+    Kosmos.Fixture { FakeConnectivityRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
index 331e2fa..c69d9a2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
@@ -42,10 +42,7 @@
      * validated
      */
     @JvmOverloads
-    fun setMobileConnected(
-        default: Boolean = true,
-        validated: Boolean = true,
-    ) {
+    fun setMobileConnected(default: Boolean = true, validated: Boolean = true) {
         defaultConnections.value =
             DefaultConnectionModel(
                 mobile = DefaultConnectionModel.Mobile(default),
@@ -55,10 +52,7 @@
 
     /** Similar convenience method for ethernet */
     @JvmOverloads
-    fun setEthernetConnected(
-        default: Boolean = true,
-        validated: Boolean = true,
-    ) {
+    fun setEthernetConnected(default: Boolean = true, validated: Boolean = true) {
         defaultConnections.value =
             DefaultConnectionModel(
                 ethernet = DefaultConnectionModel.Ethernet(default),
@@ -67,10 +61,7 @@
     }
 
     @JvmOverloads
-    fun setWifiConnected(
-        default: Boolean = true,
-        validated: Boolean = true,
-    ) {
+    fun setWifiConnected(default: Boolean = true, validated: Boolean = true) {
         defaultConnections.value =
             DefaultConnectionModel(
                 wifi = DefaultConnectionModel.Wifi(default),
@@ -78,3 +69,6 @@
             )
     }
 }
+
+val ConnectivityRepository.fake
+    get() = this as FakeConnectivityRepository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
index 385a813..13fde96 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.pipeline.shared.domain.interactor
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor
 
 val Kosmos.collapsedStatusBarInteractor: CollapsedStatusBarInteractor by
-    Kosmos.Fixture { CollapsedStatusBarInteractor(fakeDisableFlagsRepository) }
+    Kosmos.Fixture { CollapsedStatusBarInteractor(disableFlagsInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
index 528c9d9..a110a49 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
@@ -27,6 +27,9 @@
     var isAttached = false
         private set
 
+    var isStopped = false
+        private set
+
     override val statusBarHeight: Int = 0
 
     override fun refreshStatusBarHeight() {}
@@ -35,6 +38,10 @@
         isAttached = true
     }
 
+    override fun stop() {
+        isStopped = true
+    }
+
     override fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams) {}
 
     override val backgroundView: View
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
index 173e909..23f2b42 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt
@@ -18,7 +18,8 @@
 
 import android.content.testableContext
 import android.view.windowManagerService
-import com.android.app.viewcapture.viewCaptureAwareWindowManager
+import com.android.app.viewcapture.realCaptureAwareWindowManager
+import com.android.systemui.concurrency.fakeExecutor
 import com.android.systemui.fragments.fragmentService
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.phone.statusBarContentInsetsProvider
@@ -32,12 +33,13 @@
         StatusBarWindowControllerImpl(
             testableContext,
             statusBarWindowViewInflater,
-            viewCaptureAwareWindowManager,
+            realCaptureAwareWindowManager,
             statusBarConfigurationController,
             windowManagerService,
             statusBarContentInsetsProvider,
             fragmentService,
             Optional.empty(),
+            fakeExecutor,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt
new file mode 100644
index 0000000..4941ceb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.window
+
+import android.view.WindowManager
+import com.android.app.viewcapture.ViewCaptureAwareWindowManager
+import com.android.app.viewcapture.realCaptureAwareWindowManager
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.displayWindowPropertiesRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore
+import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore
+import org.mockito.kotlin.mock
+
+val Kosmos.multiDisplayStatusBarWindowControllerStore by
+    Kosmos.Fixture {
+        MultiDisplayStatusBarWindowControllerStore(
+            backgroundApplicationScope = applicationCoroutineScope,
+            controllerFactory = { _, _, _, _ -> mock() },
+            displayWindowPropertiesRepository = displayWindowPropertiesRepository,
+            viewCaptureAwareWindowManagerFactory =
+                object : ViewCaptureAwareWindowManager.Factory {
+                    override fun create(
+                        windowManager: WindowManager
+                    ): ViewCaptureAwareWindowManager {
+                        return realCaptureAwareWindowManager
+                    }
+                },
+            statusBarConfigurationControllerStore = statusBarConfigurationControllerStore,
+            statusBarContentInsetsProviderStore = statusBarContentInsetsProviderStore,
+            displayRepository = displayRepository,
+        )
+    }
diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index fe2269a..27c5ea1 100755
--- a/ravenwood/scripts/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -33,7 +33,7 @@
 exclude_re=""
 smoke_exclude_re=""
 dry_run=""
-while getopts "sx:f:dt" opt; do
+while getopts "sx:f:dtb" opt; do
 case "$opt" in
     s)
         # Remove slow tests.
@@ -52,8 +52,13 @@
         dry_run="echo"
         ;;
     t)
+        # Redirect log to terminal
         export RAVENWOOD_LOG_OUT=$(tty)
         ;;
+    b)
+        # Build only
+        ATEST=m
+        ;;
     '?')
         exit 1
         ;;
@@ -99,11 +104,16 @@
 
 # Calculate the removed tests.
 
-diff="$(diff  <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )"
+diff="$(diff  <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') | grep -v [0-9] )"
 
 if [[ "$diff" != "" ]]; then
     echo "Excluded tests:"
     echo "$diff"
 fi
 
-$dry_run ${ATEST:-atest} "${targets[@]}"
+run() {
+    echo "Running: ${@}"
+    "${@}"
+}
+
+run $dry_run ${ATEST:-atest} "${targets[@]}"
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b221d74..762665c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.appwidget;
 
+import static android.appwidget.flags.Flags.checkRemoteViewsUriPermission;
 import static android.appwidget.flags.Flags.remoteAdapterConversion;
 import static android.appwidget.flags.Flags.remoteViewsProto;
 import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
@@ -62,6 +63,7 @@
 import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Intent.FilterComparison;
@@ -150,6 +152,8 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.WidgetBackupProvider;
+import com.android.server.uri.GrantUri;
+import com.android.server.uri.UriGrantsManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -607,7 +611,8 @@
                     // ... and see if these are hosts we've been awaiting.
                     // NOTE: We are backing up and restoring only the owner.
                     // TODO: http://b/22388012
-                    if (newPackageAdded && userId == UserHandle.USER_SYSTEM) {
+                    UserHandle mainUser = mUserManager.getMainUser();
+                    if (newPackageAdded && mainUser != null && userId == mainUser.getIdentifier()) {
                         final int uid = getUidForPackage(pkgName, userId);
                         if (uid >= 0 ) {
                             resolveHostUidLocked(pkgName, uid);
@@ -2547,6 +2552,10 @@
 
         // Make sure the package runs under the caller uid.
         mSecurityPolicy.enforceCallFromPackage(callingPackage);
+        // Make sure RemoteViews do not contain URIs that the caller cannot access.
+        if (checkRemoteViewsUriPermission()) {
+            checkRemoteViewsUris(views);
+        }
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
 
@@ -2567,6 +2576,39 @@
     }
 
     /**
+     * Checks that all of the Uris in the given RemoteViews are accessible to the caller.
+     */
+    private void checkRemoteViewsUris(RemoteViews views) {
+        UriGrantsManagerInternal uriGrantsManager = LocalServices.getService(
+                UriGrantsManagerInternal.class);
+        int callingUid = Binder.getCallingUid();
+        int callingUser = UserHandle.getCallingUserId();
+        views.visitUris(uri -> {
+            switch (uri.getScheme()) {
+                // Check that content:// URIs are accessible to the caller.
+                case ContentResolver.SCHEME_CONTENT:
+                    boolean canAccessUri = uriGrantsManager.checkUriPermission(
+                            GrantUri.resolve(callingUser, uri,
+                                    Intent.FLAG_GRANT_READ_URI_PERMISSION), callingUid,
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                            /* isFullAccessForContentUri= */ true);
+                    if (!canAccessUri) {
+                        throw new SecurityException(
+                                "Provider uid " + callingUid + " cannot access URI " + uri);
+                    }
+                    break;
+                // android.resource:// URIs are always allowed.
+                case ContentResolver.SCHEME_ANDROID_RESOURCE:
+                    break;
+                // file:// and any other schemes are disallowed.
+                case ContentResolver.SCHEME_FILE:
+                default:
+                    throw new SecurityException("Disallowed URI " + uri + " in RemoteViews.");
+            }
+        });
+    }
+
+    /**
      * Increment the counter of widget ids and return the new id.
      *
      * Typically called by {@link #allocateAppWidgetId} when a instance of widget is created,
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index bd46deb..b3fe5f2 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -2,6 +2,13 @@
 container: "system"
 
 flag {
+  name: "autofill_w_metrics"
+  namespace: "autofill"
+  description: "Guards against new metrics definitions introduced in W"
+  bug: "342676602"
+}
+
+flag {
   name: "autofill_credman_integration"
   namespace: "autofill"
   description: "Guards Autofill Framework against Autofill-Credman integration"
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index cd2a535..e59bb42 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -28,8 +28,11 @@
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.WindowNode;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
 import android.content.ComponentName;
 import android.content.Context;
+import android.graphics.drawable.Icon;
 import android.hardware.display.DisplayManager;
 import android.metrics.LogMaker;
 import android.os.UserHandle;
@@ -97,11 +100,12 @@
             @UserIdInt int userId, @NonNull RemoteViews rView) {
         final AtomicBoolean permissionsOk = new AtomicBoolean(true);
 
-        rView.visitUris(uri -> {
-            int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
-            boolean allowed = uriOwnerId == userId;
-            permissionsOk.set(allowed & permissionsOk.get());
-        });
+        rView.visitUris(
+                uri -> {
+                    int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri, userId);
+                    boolean allowed = uriOwnerId == userId;
+                    permissionsOk.set(allowed & permissionsOk.get());
+                });
 
         return permissionsOk.get();
     }
@@ -150,6 +154,47 @@
         return (ok ? rView : null);
     }
 
+    /**
+     * Checks the URI permissions of the icon in the slice, to see if the current userId is able to
+     * access it.
+     *
+     * <p>Returns null if slice contains user inaccessible icons
+     *
+     * <p>TODO: instead of returning a null Slice when the current userId cannot access an icon,
+     * return a reconstructed Slice without the icons. This is currently non-trivial since there are
+     * no public methods to generically add SliceItems to Slices
+     */
+    public static @Nullable Slice sanitizeSlice(Slice slice) {
+        if (slice == null) {
+            return null;
+        }
+
+        int userId = ActivityManager.getCurrentUser();
+
+        // Recontruct the Slice, filtering out bad icons
+        for (SliceItem sliceItem : slice.getItems()) {
+            if (!sliceItem.getFormat().equals(SliceItem.FORMAT_IMAGE)) {
+                // Not an image slice
+                continue;
+            }
+
+            Icon icon = sliceItem.getIcon();
+            if (icon.getType() != Icon.TYPE_URI
+                    && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+                // No URIs to sanitize
+                continue;
+            }
+
+            int iconUriId = android.content.ContentProvider.getUserIdFromUri(icon.getUri(), userId);
+
+            if (iconUriId != userId) {
+                Slog.w(TAG, "sanitizeSlice() user: " + userId + " cannot access icons in Slice");
+                return null;
+            }
+        }
+
+        return slice;
+    }
 
     @Nullable
     static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
index 38a412f..50a26b3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
+++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java
@@ -27,6 +27,7 @@
 import android.util.Slog;
 
 import com.android.server.LocalServices;
+import com.android.server.autofill.Helper;
 import com.android.server.autofill.RemoteInlineSuggestionRenderService;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 
@@ -83,6 +84,10 @@
      */
     public boolean renderSuggestion(int width, int height,
             @NonNull IInlineSuggestionUiCallback callback) {
+        if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) {
+            if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion.");
+            return false;
+        }
         if (mRemoteRenderService != null) {
             if (sDebug) Slog.d(TAG, "Request to recreate the UI");
             mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index d53f949..fcb7934 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -60,3 +60,12 @@
     bug: "331749778"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_restricted_mode_changes"
+    namespace: "onboarding"
+    description: "Enables the new framework behavior of not putting apps in restricted mode for "
+            "B&R operations in certain cases."
+    bug: "376661510"
+    is_fixed_read_only: true
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 466d477..5de2fb3 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -43,6 +43,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
+import android.app.ApplicationThreadConstants;
 import android.app.IActivityManager;
 import android.app.IBackupAgent;
 import android.app.PendingIntent;
@@ -59,6 +60,9 @@
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.app.backup.ISelectBackupTransportCallback;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -298,6 +302,15 @@
     private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
     private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
 
+    /**
+     * Enables the OS making a decision on whether backup restricted mode should be used for apps
+     * that haven't explicitly opted in or out. See
+     * {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE} for details.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
+    public static final long OS_DECIDES_BACKUP_RESTRICTED_MODE = 376661510;
+
     // Time delay for initialization operations that can be delayed so as not to consume too much
     // CPU on bring-up and increase time-to-UI.
     private static final long INITIALIZATION_DELAY_MILLIS = 3000;
@@ -352,6 +365,9 @@
     // Backups that we haven't started yet.  Keys are package names.
     private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>();
 
+    private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>();
+    private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>();
+
     // locking around the pending-backup management
     private final Object mQueueLock = new Object();
 
@@ -523,7 +539,8 @@
     @VisibleForTesting
     UserBackupManagerService(Context context, PackageManager packageManager,
             LifecycleOperationStorage operationStorage, TransportManager transportManager,
-            BackupHandler backupHandler, BackupManagerConstants backupManagerConstants) {
+            BackupHandler backupHandler, BackupManagerConstants backupManagerConstants,
+            IActivityManager activityManager, ActivityManagerInternal activityManagerInternal) {
         mContext = context;
 
         mUserId = 0;
@@ -534,6 +551,8 @@
         mFullBackupQueue = new ArrayList<>();
         mBackupHandler = backupHandler;
         mConstants = backupManagerConstants;
+        mActivityManager = activityManager;
+        mActivityManagerInternal = activityManagerInternal;
 
         mBaseStateDir = null;
         mDataDir = null;
@@ -543,13 +562,11 @@
         mRunInitReceiver = null;
         mRunInitIntent = null;
         mAgentTimeoutParameters = null;
-        mActivityManagerInternal = null;
         mAlarmManager = null;
         mWakelock = null;
         mBackupPreferences = null;
         mBackupPasswordManager = null;
         mPackageManagerBinder = null;
-        mActivityManager = null;
         mBackupManagerBinder = null;
         mScheduledBackupEligibility = null;
     }
@@ -1651,9 +1668,11 @@
         synchronized (mAgentConnectLock) {
             mConnecting = true;
             mConnectedAgent = null;
+            boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode,
+                    app.packageName);
             try {
                 if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
-                        backupDestination)) {
+                        backupDestination, useRestrictedMode)) {
                     Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));
 
                     // success; wait for the agent to arrive
@@ -3103,6 +3122,91 @@
         }
     }
 
+    /**
+     * Marks the given set of packages as packages that should not be put into restricted mode if
+     * they are started for the given {@link BackupAnnotations.OperationType}.
+     */
+    public void setNoRestrictedModePackages(Set<String> packageNames,
+            @BackupAnnotations.OperationType int opType) {
+        if (opType == BackupAnnotations.OperationType.BACKUP) {
+            mBackupNoRestrictedModePackages.clear();
+            mBackupNoRestrictedModePackages.addAll(packageNames);
+        } else if (opType == BackupAnnotations.OperationType.RESTORE) {
+            mRestoreNoRestrictedModePackages.clear();
+            mRestoreNoRestrictedModePackages.addAll(packageNames);
+        } else {
+            throw new IllegalArgumentException("opType must be BACKUP or RESTORE");
+        }
+    }
+
+    /**
+     * Clears the list of packages that should not be put into restricted mode for either backup or
+     * restore.
+     */
+    public void clearNoRestrictedModePackages() {
+        mBackupNoRestrictedModePackages.clear();
+        mRestoreNoRestrictedModePackages.clear();
+    }
+
+    /**
+     * If the app has specified {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE}, then
+     * its value is returned. If it hasn't and it targets an SDK below
+     * {@link Build.VERSION_CODES#BAKLAVA} then returns true. If it targets a newer SDK, then
+     * returns the decision made by the {@link android.app.backup.BackupTransport}.
+     *
+     * <p>When this method is called, we should have already asked the transport and cached its
+     * response in {@link #mBackupNoRestrictedModePackages} or
+     * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without
+     * any IPC to the transport.
+     */
+    private boolean shouldUseRestrictedBackupModeForPackage(
+            @BackupAnnotations.OperationType int mode, String packageName) {
+        if (!Flags.enableRestrictedModeChanges()) {
+            return true;
+        }
+
+        // Key/Value apps are never put in restricted mode.
+        if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+                || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) {
+            return false;
+        }
+
+        try {
+            PackageManager.Property property = mPackageManager.getPropertyAsUser(
+                    PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE,
+                    packageName, /* className= */ null,
+                    mUserId);
+            if (property.isBoolean()) {
+                // If the package has explicitly specified, we won't ask the transport.
+                return property.getBoolean();
+            } else {
+                Slog.w(TAG, PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE
+                        + "must be a boolean.");
+            }
+        } catch (NameNotFoundException e) {
+            // This is expected when the package has not defined the property in its manifest.
+        }
+
+        // The package has not specified the property. The behavior depends on the package's
+        // targetSdk.
+        // <36 gets the old behavior of always using restricted mode.
+        if (!CompatChanges.isChangeEnabled(OS_DECIDES_BACKUP_RESTRICTED_MODE, packageName,
+                UserHandle.of(mUserId))) {
+            return true;
+        }
+
+        // Apps targeting >=36 get the behavior decided by the transport.
+        // By this point, we should have asked the transport and cached its decision.
+        if ((mode == ApplicationThreadConstants.BACKUP_MODE_FULL
+                && mBackupNoRestrictedModePackages.contains(packageName))
+                || (mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL
+                && mRestoreNoRestrictedModePackages.contains(packageName))) {
+            Slog.d(TAG, "Transport requested no restricted mode for: " + packageName);
+            return false;
+        }
+        return true;
+    }
+
     private boolean startConfirmationUi(int token, String action) {
         try {
             Intent confIntent = new Intent(action);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index cca166b..be9cdc8 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -16,6 +16,8 @@
 
 package com.android.server.backup.fullbackup;
 
+import static android.app.backup.BackupAnnotations.OperationType.BACKUP;
+
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
@@ -34,6 +36,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -388,6 +391,10 @@
                 }
             }
 
+            // We ask the transport which packages should not be put in restricted mode and cache
+            // the result in UBMS to be used later when the apps are started for backup.
+            setNoRestrictedModePackages(transport, mPackages);
+
             // Set up to send data to the transport
             final int N = mPackages.size();
             int chunkSizeInBytes = 8 * 1024; // 8KB
@@ -694,6 +701,9 @@
                 mUserBackupManagerService.scheduleNextFullBackupJob(backoff);
             }
 
+            // Clear this to avoid using the memory until reboot.
+            mUserBackupManagerService.clearNoRestrictedModePackages();
+
             Slog.i(TAG, "Full data backup pass finished.");
             mUserBackupManagerService.getWakelock().release();
         }
@@ -722,6 +732,21 @@
         }
     }
 
+    private void setNoRestrictedModePackages(BackupTransportClient transport,
+            List<PackageInfo> packages) {
+        try {
+            Set<String> packageNames = new ArraySet<>();
+            for (int i = 0; i < packages.size(); i++) {
+                packageNames.add(packages.get(i).packageName);
+            }
+            packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+                    BACKUP);
+            mUserBackupManagerService.setNoRestrictedModePackages(packageNames, BACKUP);
+        } catch (RemoteException e) {
+            Slog.i(TAG, "Failed to retrieve no restricted mode packages from transport");
+        }
+    }
+
     // Run the backup and pipe it back to the given socket -- expects to run on
     // a standalone thread.  The  runner owns this half of the pipe, and closes
     // it to indicate EOD to the other end.
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index e536876..5ee51a5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -53,6 +53,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -482,6 +483,10 @@
                 return;
             }
 
+            // We ask the transport which packages should not be put in restricted mode and cache
+            // the result in UBMS to be used later when the apps are started for restore.
+            setNoRestrictedModePackages(transport, packages);
+
             RestoreDescription desc = transport.nextRestorePackage();
             if (desc == null) {
                 Slog.e(TAG, "No restore metadata available; halting");
@@ -1358,6 +1363,9 @@
         // Clear any ongoing session timeout.
         backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
 
+        // Clear this to avoid using the memory until reboot.
+        backupManagerService.clearNoRestrictedModePackages();
+
         // If we have a PM token, we must under all circumstances be sure to
         // handshake when we've finished.
         if (mPmToken > 0) {
@@ -1819,4 +1827,20 @@
 
         return packageInfo;
     }
+
+    @VisibleForTesting
+    void setNoRestrictedModePackages(BackupTransportClient transport,
+            PackageInfo[] packages) {
+        try {
+            Set<String> packageNames = new ArraySet<>();
+            for (int i = 0; i < packages.length; i++) {
+                packageNames.add(packages[i].packageName);
+            }
+            packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames,
+                    RESTORE);
+            backupManagerService.setNoRestrictedModePackages(packageNames, RESTORE);
+        } catch (RemoteException e) {
+            Slog.i(TAG, "Failed to retrieve restricted mode packages from transport");
+        }
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
index daf34152..373811f 100644
--- a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java
@@ -17,6 +17,7 @@
 package com.android.server.backup.transport;
 
 import android.annotation.Nullable;
+import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupTransport;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.RestoreDescription;
@@ -26,6 +27,7 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.backup.IBackupTransport;
@@ -375,6 +377,26 @@
     }
 
     /**
+     * See
+     * {@link IBackupTransport#getPackagesThatShouldNotUseRestrictedMode(List, int, AndroidFuture)}.
+     */
+    public Set<String> getPackagesThatShouldNotUseRestrictedMode(Set<String> packageNames,
+            @BackupAnnotations.OperationType
+            int operationType) throws RemoteException {
+        AndroidFuture<List<String>> resultFuture = mTransportFutures.newFuture();
+        mTransportBinder.getPackagesThatShouldNotUseRestrictedMode(List.copyOf(packageNames),
+                operationType,
+                resultFuture);
+        List<String> resultList = getFutureResult(resultFuture);
+        Set<String> set = new ArraySet<>();
+        if (resultList == null) {
+            return set;
+        }
+        set.addAll(resultList);
+        return set;
+    }
+
+    /**
      * Allows the {@link TransportConnection} to notify this client
      * if the underlying transport has become unusable.  If that happens
      * we want to cancel all active futures or callbacks.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cb89f28..d880bce 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -478,7 +478,6 @@
 
 import dalvik.annotation.optimization.NeverCompile;
 import dalvik.system.VMRuntime;
-
 import libcore.util.EmptyArray;
 
 import java.io.File;
@@ -668,6 +667,8 @@
      */
     private static final boolean ENABLE_PROC_LOCK = true;
 
+    private static final int DEFAULT_INTENT_CREATOR_UID = -1;
+
     /**
      * The lock for process management.
      *
@@ -4491,16 +4492,11 @@
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 final int userId = app.userId;
                 final String packageName = app.info.packageName;
-                mHandler.post(new Runnable() {
-                @Override
-                    public void run() {
-                        try {
-                            IBackupManager bm = IBackupManager.Stub.asInterface(
-                                    ServiceManager.getService(Context.BACKUP_SERVICE));
-                            bm.agentDisconnectedForUser(userId, packageName);
-                        } catch (RemoteException e) {
-                            // Can't happen; the backup manager is local
-                        }
+                mHandler.post(() -> {
+                    try {
+                        getBackupManager().agentDisconnectedForUser(userId, packageName);
+                    } catch (RemoteException e) {
+                        // Can't happen; the backup manager is local
                     }
                 });
             }
@@ -4671,7 +4667,8 @@
             if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
                 isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
                         && ((backupTarget.backupMode == BackupRecord.RESTORE_FULL)
-                                || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
+                        || (backupTarget.backupMode == BackupRecord.BACKUP_FULL))
+                        && backupTarget.useRestrictedMode;
             }
 
             final ActiveInstrumentation instr = app.getActiveInstrumentation();
@@ -13497,16 +13494,11 @@
         if (backupTarget != null && pid == backupTarget.app.getPid()) {
             if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
                     + backupTarget.appInfo + " died during backup");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        IBackupManager bm = IBackupManager.Stub.asInterface(
-                                ServiceManager.getService(Context.BACKUP_SERVICE));
-                        bm.agentDisconnectedForUser(app.userId, app.info.packageName);
-                    } catch (RemoteException e) {
-                        // can't happen; backup manager is local
-                    }
+            mHandler.post(() -> {
+                try {
+                    getBackupManager().agentDisconnectedForUser(app.userId, app.info.packageName);
+                } catch (RemoteException e) {
+                    // can't happen; backup manager is local
                 }
             });
         }
@@ -14009,7 +14001,7 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
-            @BackupDestination int backupDestination) {
+            @BackupDestination int backupDestination, boolean useRestrictedMode) {
         long startTimeNs = SystemClock.uptimeNanos();
         if (DEBUG_BACKUP) {
             Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
@@ -14094,7 +14086,8 @@
                         + app.packageName + ": " + e);
             }
 
-            BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination);
+            BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination,
+                    useRestrictedMode);
             ComponentName hostingName =
                     (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
                             || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE)
@@ -14120,8 +14113,9 @@
             // process, etc, then mark it as being in full backup so that certain calls to the
             // process can be blocked. This is not reset to false anywhere because we kill the
             // process after the full backup is done and the ProcessRecord will vaporize anyway.
-            if (UserHandle.isApp(app.uid) &&
-                    backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL) {
+            if (UserHandle.isApp(app.uid)
+                    && backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL
+                    && r.useRestrictedMode) {
                 proc.setInFullBackup(true);
             }
             r.app = proc;
@@ -14219,9 +14213,7 @@
 
         final long oldIdent = Binder.clearCallingIdentity();
         try {
-            IBackupManager bm = IBackupManager.Stub.asInterface(
-                    ServiceManager.getService(Context.BACKUP_SERVICE));
-            bm.agentConnectedForUser(userId, agentPackageName, agent);
+            getBackupManager().agentConnectedForUser(userId, agentPackageName, agent);
         } catch (RemoteException e) {
             // can't happen; the backup manager service is local
         } catch (Exception e) {
@@ -18011,14 +18003,6 @@
         @Override
         public void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid,
                 int userId) {
-            // For the simplification, we don't support USER_ALL nor USER_CURRENT here.
-            if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_CURRENT) {
-                throw new IllegalArgumentException("Unsupported userId");
-            }
-
-            mUserController.handleIncomingUser(pid, uid, userId, true,
-                    ALLOW_NON_FULL, "addStartInfoTimestampSystem", null);
-
             addStartInfoTimestampInternal(key, timestampNs, userId, uid);
         }
 
@@ -19308,22 +19292,36 @@
         if (!preventIntentRedirect()) return;
 
         if (intent == null) return;
+
+        String targetPackage = intent.getComponent() != null
+                ? intent.getComponent().getPackageName()
+                : intent.getPackage();
+        final boolean isCreatorSameAsTarget = creatorPackage != null && creatorPackage.equals(
+                targetPackage);
+        final boolean noExtraIntentKeys =
+                intent.getExtraIntentKeys() == null || intent.getExtraIntentKeys().isEmpty();
+        final int creatorUid = noExtraIntentKeys ? DEFAULT_INTENT_CREATOR_UID : Binder.getCallingUid();
+
         intent.forEachNestedCreatorToken(extraIntent -> {
-            IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorPackage);
+            if (isCreatorSameAsTarget) {
+                FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, true);
+                return;
+            }
+            IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorUid,
+                    creatorPackage);
             if (creatorToken != null) {
                 extraIntent.setCreatorToken(creatorToken);
                 // TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329
                 Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: "
                         + creatorPackage + "; intent: " + extraIntent);
-                FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED,
-                        creatorToken.getCreatorUid());
+                FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, false);
             }
         });
     }
 
-    private IntentCreatorToken createIntentCreatorToken(Intent intent, String creatorPackage) {
+    private IntentCreatorToken createIntentCreatorToken(Intent intent, int creatorUid,
+            String creatorPackage) {
         if (IntentCreatorToken.isValid(intent)) return null;
-        int creatorUid = getCallingUid();
         IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, creatorPackage, intent);
         IntentCreatorToken token;
         synchronized (sIntentCreatorTokenCache) {
@@ -19337,4 +19335,8 @@
         }
         return token;
     }
+
+    private IBackupManager getBackupManager() {
+        return IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
+    }
 }
diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java
index 0b056d7..64cc6f0 100644
--- a/services/core/java/com/android/server/am/BackupRecord.java
+++ b/services/core/java/com/android/server/am/BackupRecord.java
@@ -32,15 +32,18 @@
     final int userId;                      // user for which backup is performed
     final int backupMode;                  // full backup / incremental / restore
     @BackupDestination final int backupDestination; // see BackupAnnotations#BackupDestination
+    final boolean useRestrictedMode; // whether the app should be put into restricted backup mode
     ProcessRecord app;                     // where this agent is running or null
 
     // ----- Implementation -----
 
-    BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination) {
+    BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination,
+            boolean _useRestrictedMode) {
         appInfo = _appInfo;
         backupMode = _backupMode;
         userId = _userId;
         backupDestination = _backupDestination;
+        useRestrictedMode = _useRestrictedMode;
     }
 
     public String toString() {
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java
index 8a12858..c6cb67f 100644
--- a/services/core/java/com/android/server/am/BroadcastController.java
+++ b/services/core/java/com/android/server/am/BroadcastController.java
@@ -57,7 +57,6 @@
 import android.app.ApplicationThreadConstants;
 import android.app.BackgroundStartPrivileges;
 import android.app.BroadcastOptions;
-import android.app.BroadcastStickyCache;
 import android.app.IApplicationThread;
 import android.app.compat.CompatChanges;
 import android.appwidget.AppWidgetManager;
@@ -554,7 +553,7 @@
             }
             BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                     receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
-                    exported, mService.mPlatformCompat);
+                    exported, callerApp.info, mService.mPlatformCompat);
             if (rl.containsFilter(filter)) {
                 Slog.w(TAG, "Receiver with filter " + filter
                         + " already registered for pid " + rl.pid
@@ -702,7 +701,6 @@
             boolean serialized, boolean sticky, int userId) {
         mService.enforceNotIsolatedCaller("broadcastIntent");
 
-        int result;
         synchronized (mService) {
             intent = verifyBroadcastLocked(intent);
 
@@ -724,7 +722,7 @@
 
             final long origId = Binder.clearCallingIdentity();
             try {
-                result = broadcastIntentLocked(callerApp,
+                return broadcastIntentLocked(callerApp,
                         callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                         intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
                         resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
@@ -735,10 +733,6 @@
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
-        if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
-            BroadcastStickyCache.incrementVersion(intent.getAction());
-        }
-        return result;
     }
 
     // Not the binder call surface
@@ -749,7 +743,6 @@
             boolean serialized, boolean sticky, int userId,
             BackgroundStartPrivileges backgroundStartPrivileges,
             @Nullable int[] broadcastAllowList) {
-        int result;
         synchronized (mService) {
             intent = verifyBroadcastLocked(intent);
 
@@ -757,7 +750,7 @@
             String[] requiredPermissions = requiredPermission == null ? null
                     : new String[] {requiredPermission};
             try {
-                result = broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
+                return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType,
                         resultToApp, resultTo, resultCode, resultData, resultExtras,
                         requiredPermissions, null, null, OP_NONE, bOptions, serialized, sticky, -1,
                         uid, realCallingUid, realCallingPid, userId,
@@ -767,10 +760,6 @@
                 Binder.restoreCallingIdentity(origId);
             }
         }
-        if (sticky && result == ActivityManager.BROADCAST_SUCCESS) {
-            BroadcastStickyCache.incrementVersion(intent.getAction());
-        }
-        return result;
     }
 
     @GuardedBy("mService")
@@ -1469,7 +1458,6 @@
                     list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive,
                             callingUid, callerAppProcessState, resolvedType));
                 }
-                BroadcastStickyCache.incrementVersion(intent.getAction());
             }
         }
 
@@ -1736,7 +1724,6 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
         synchronized (mStickyBroadcasts) {
             ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);
             if (stickies != null) {
@@ -1753,16 +1740,12 @@
                     if (list.size() <= 0) {
                         stickies.remove(intent.getAction());
                     }
-                    changedStickyBroadcasts.add(intent.getAction());
                 }
                 if (stickies.size() <= 0) {
                     mStickyBroadcasts.remove(userId);
                 }
             }
         }
-        for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
-            BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i));
-        }
     }
 
     void finishReceiver(IBinder caller, int resultCode, String resultData,
@@ -1925,9 +1908,7 @@
 
     private void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
         mService.mProcessList.sendPackageBroadcastLocked(cmd, packages, userId);
-    }
-
-    private List<ResolveInfo> collectReceiverComponents(
+    }private List<ResolveInfo> collectReceiverComponents(
             Intent intent, String resolvedType, int callingUid, int callingPid,
             int[] users, int[] broadcastAllowList) {
         // TODO: come back and remove this assumption to triage all broadcasts
@@ -2143,18 +2124,9 @@
     }
 
     void removeStickyBroadcasts(int userId) {
-        final ArrayList<String> changedStickyBroadcasts = new ArrayList<>();
         synchronized (mStickyBroadcasts) {
-            final ArrayMap<String, ArrayList<StickyBroadcast>> stickies =
-                    mStickyBroadcasts.get(userId);
-            if (stickies != null) {
-                changedStickyBroadcasts.addAll(stickies.keySet());
-            }
             mStickyBroadcasts.remove(userId);
         }
-        for (int i = changedStickyBroadcasts.size() - 1; i >= 0; --i) {
-            BroadcastStickyCache.incrementVersionIfExists(changedStickyBroadcasts.get(i));
-        }
     }
 
     @NeverCompile
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 3c7fb52..a32d3cb 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -16,10 +16,13 @@
 
 package com.android.server.am;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.os.Binder;
 import android.os.UserHandle;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -40,7 +43,7 @@
     @ChangeId
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
     @VisibleForTesting
-    static final long CHANGE_RESTRICT_PRIORITY_VALUES = 371309185L;
+    static final long RESTRICT_PRIORITY_VALUES = 371309185L;
 
     // Back-pointer to the list this filter is in.
     final ReceiverList receiverList;
@@ -54,11 +57,12 @@
     final boolean visibleToInstantApp;
     public final boolean exported;
     final int initialPriority;
+    final ApplicationInfo applicationInfo;
 
     BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
             String _packageName, String _featureId, String _receiverId, String _requiredPermission,
             int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
-            boolean _exported, PlatformCompat platformCompat) {
+            boolean _exported, ApplicationInfo _applicationInfo, PlatformCompat platformCompat) {
         super(_filter);
         receiverList = _receiverList;
         packageName = _packageName;
@@ -70,8 +74,10 @@
         instantApp = _instantApp;
         visibleToInstantApp = _visibleToInstantApp;
         exported = _exported;
+        applicationInfo = _applicationInfo;
         initialPriority = getPriority();
-        setPriority(calculateAdjustedPriority(owningUid, initialPriority, platformCompat));
+        setPriority(calculateAdjustedPriority(owningUid, initialPriority,
+                applicationInfo, platformCompat));
     }
 
     public @Nullable String getReceiverClassName() {
@@ -84,6 +90,10 @@
         return null;
     }
 
+    public @NonNull ApplicationInfo getApplicationInfo() {
+        return applicationInfo;
+    }
+
     @NeverCompile
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
@@ -125,13 +135,18 @@
 
     @VisibleForTesting
     static int calculateAdjustedPriority(int owningUid, int priority,
-            PlatformCompat platformCompat) {
+            ApplicationInfo applicationInfo, PlatformCompat platformCompat) {
         if (!Flags.restrictPriorityValues()) {
             return priority;
         }
-        if (!platformCompat.isChangeEnabledByUidInternalNoLogging(
-                CHANGE_RESTRICT_PRIORITY_VALUES, owningUid)) {
-            return priority;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (!platformCompat.isChangeEnabledInternalNoLogging(
+                    RESTRICT_PRIORITY_VALUES, applicationInfo)) {
+                return priority;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
         if (!UserHandle.isCore(owningUid)) {
             if (priority >= SYSTEM_HIGH_PRIORITY) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 38df10a..a1ab1eea 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -49,6 +49,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
 import android.os.Bundle;
@@ -57,7 +58,6 @@
 import android.util.ArrayMap;
 import android.util.IntArray;
 import android.util.PrintWriterPrinter;
-import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -88,7 +88,7 @@
     @ChangeId
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
     @VisibleForTesting
-    static final long CHANGE_LIMIT_PRIORITY_SCOPE = 371307720L;
+    static final long LIMIT_PRIORITY_SCOPE = 371307720L;
 
     final @NonNull Intent intent;    // the original intent that generated us
     final @Nullable ComponentName targetComp; // original component name set on the intent
@@ -781,7 +781,7 @@
         } else {
             if (Flags.limitPriorityScope()) {
                 final boolean[] changeEnabled = calculateChangeStateForReceivers(
-                        receivers, CHANGE_LIMIT_PRIORITY_SCOPE, platformCompat);
+                        receivers, LIMIT_PRIORITY_SCOPE, platformCompat);
 
                 // Priority of the previous tranche
                 int lastTranchePriority = 0;
@@ -865,25 +865,35 @@
     @VisibleForTesting
     static @NonNull boolean[] calculateChangeStateForReceivers(@NonNull List<Object> receivers,
             long changeId, PlatformCompat platformCompat) {
-        final SparseBooleanArray changeStateForUids = new SparseBooleanArray();
+        // TODO: b/371307720 - Remove this method as we are already avoiding the packagemanager
+        // calls by checking the changeId state using ApplicationInfos.
+        final ArrayMap<String, Boolean> changeStates = new ArrayMap<>();
         final int count = receivers.size();
         final boolean[] changeStateForReceivers = new boolean[count];
         for (int i = 0; i < count; ++i) {
-            final int receiverUid = getReceiverUid(receivers.get(i));
+            final ApplicationInfo receiverAppInfo = getReceiverAppInfo(receivers.get(i));
             final boolean isChangeEnabled;
-            final int idx = changeStateForUids.indexOfKey(receiverUid);
+            final int idx = changeStates.indexOfKey(receiverAppInfo.packageName);
             if (idx >= 0) {
-                isChangeEnabled = changeStateForUids.valueAt(idx);
+                isChangeEnabled = changeStates.valueAt(idx);
             } else {
-                isChangeEnabled = platformCompat.isChangeEnabledByUidInternalNoLogging(
-                        changeId, receiverUid);
-                changeStateForUids.put(receiverUid, isChangeEnabled);
+                isChangeEnabled = platformCompat.isChangeEnabledInternalNoLogging(
+                        changeId, receiverAppInfo);
+                changeStates.put(receiverAppInfo.packageName, isChangeEnabled);
             }
             changeStateForReceivers[i] = isChangeEnabled;
         }
         return changeStateForReceivers;
     }
 
+    static ApplicationInfo getReceiverAppInfo(@NonNull Object receiver) {
+        if (receiver instanceof BroadcastFilter) {
+            return ((BroadcastFilter) receiver).getApplicationInfo();
+        } else {
+            return ((ResolveInfo) receiver).activityInfo.applicationInfo;
+        }
+    }
+
     static int getReceiverUid(@NonNull Object receiver) {
         if (receiver instanceof BroadcastFilter) {
             return ((BroadcastFilter) receiver).owningUid;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b51db13..98f738c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -351,7 +351,8 @@
     private String[] mIsolatedEntryPointArgs;
 
     /**
-     * Process is currently hosting a backup agent for backup or restore.
+     * Process is currently hosting a backup agent for backup or restore. Note that this is only set
+     * when the process is put into restricted backup mode.
      */
     @GuardedBy("mService")
     private boolean mInFullBackup;
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 3644974..14d3fbc 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -393,6 +393,8 @@
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
             } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                 adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+            } else if (Flags.addModifyRawOomAdjServiceLevel() && adj < ProcessList.SERVICE_ADJ) {
+                adj = ProcessList.SERVICE_ADJ;
             } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
                 adj = ProcessList.CACHED_APP_MIN_ADJ;
             } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 3dd5ec9..ef5296e 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -221,6 +221,7 @@
         "preload_safety",
         "printing",
         "privacy_infra_policy",
+        "psap_ai",
         "ravenwood",
         "resource_manager",
         "responsible_apis",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 711b163..c59c40f 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -260,3 +260,13 @@
     description: "Use PROCESS_CAPABILITY_CPU_TIME to control unfreeze state."
     bug: "370817323"
 }
+
+flag {
+    name: "add_modify_raw_oom_adj_service_level"
+    namespace: "backstage_power"
+    description: "Add a SERVICE_ADJ level to the modifyRawOomAdj method"
+    bug: "374810368"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6ba3569..5f71660 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9224,6 +9224,9 @@
                 return;
             }
 
+            // index values sent to APM are in the stream type SDK range, not *10
+            int indexMinVolCurve = MIN_STREAM_VOLUME[mStreamType];
+            int indexMaxVolCurve = MAX_STREAM_VOLUME[mStreamType];
             synchronized (this) {
                 if (mStreamType == AudioSystem.STREAM_VOICE_CALL) {
                     if (MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]
@@ -9234,11 +9237,15 @@
                     if (!equalScoLeaVcIndexRange() && isStreamBluetoothSco(mStreamType)) {
                         // SCO devices have a different min index
                         mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+                        indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
+                        indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
                         mIndexStepFactor = 1.f;
                     } else if (equalScoLeaVcIndexRange() && isStreamBluetoothComm(mStreamType)) {
                         // For non SCO devices the stream state does not change the min index
                         if (mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) {
                             mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+                            indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
+                            indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO];
                         } else {
                             mIndexMin = MIN_STREAM_VOLUME[mStreamType] * 10;
                         }
@@ -9259,7 +9266,7 @@
             }
 
             final int status = AudioSystem.initStreamVolume(
-                    mStreamType, mIndexMin / 10, mIndexMax / 10);
+                    mStreamType, indexMinVolCurve, indexMaxVolCurve);
             sVolumeLogger.enqueue(new EventLogger.StringEvent(
                     "updateIndexFactors() stream:" + mStreamType + " index min/max:"
                             + mIndexMin / 10 + "/" + mIndexMax / 10 + " indexStepFactor:"
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b63b07f..e92b518 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -20,6 +20,7 @@
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_APP_OPS;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_CLIENT_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_MASTER;
+import static android.media.AudioPlaybackConfiguration.MUTED_BY_PORT_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_MUTED;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_VOLUME;
 import static android.media.AudioPlaybackConfiguration.MUTED_BY_VOLUME_SHAPER;
@@ -444,7 +445,7 @@
         }
 
         if (DEBUG) {
-            Log.v(TAG, TextUtils.formatSimple("BLA portEvent(portId=%d, event=%s, extras=%s)",
+            Log.v(TAG, TextUtils.formatSimple("portEvent(portId=%d, event=%s, extras=%s)",
                     portId, AudioPlaybackConfiguration.playerStateToString(event), extras));
         }
 
@@ -1381,6 +1382,9 @@
                         if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
                             builder.append("volumeShaper ");
                         }
+                        if ((mEventValue & MUTED_BY_PORT_VOLUME) != 0) {
+                            builder.append("portVolume ");
+                        }
                     }
                     return builder.toString();
                 default:
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 6578023..97a8854 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -101,6 +101,7 @@
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
 
 /**
@@ -132,7 +133,7 @@
     IGateKeeperService mGateKeeper;
 
     // Get and cache the available biometric authenticators and their associated info.
-    final ArrayList<BiometricSensor> mSensors = new ArrayList<>();
+    final CopyOnWriteArrayList<BiometricSensor> mSensors = new CopyOnWriteArrayList<>();
 
     @VisibleForTesting
     BiometricStrengthController mBiometricStrengthController;
@@ -156,13 +157,13 @@
         @NonNull private final Set<Integer> mSensorsPendingInvalidation;
 
         public static InvalidationTracker start(@NonNull Context context,
-                @NonNull ArrayList<BiometricSensor> sensors,
-                int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
+                @NonNull List<BiometricSensor> sensors, int userId,
+                int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
             return new InvalidationTracker(context, sensors, userId, fromSensorId, clientCallback);
         }
 
         private InvalidationTracker(@NonNull Context context,
-                @NonNull ArrayList<BiometricSensor> sensors, int userId,
+                @NonNull List<BiometricSensor> sensors, int userId,
                 int fromSensorId, @NonNull IInvalidationCallback clientCallback) {
             mClientCallback = clientCallback;
             mSensorsPendingInvalidation = new ArraySet<>();
@@ -879,7 +880,7 @@
 
         @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
         @Override
-        public synchronized void registerAuthenticator(int id, int modality,
+        public void registerAuthenticator(int id, int modality,
                 @Authenticators.Types int strength,
                 @NonNull IBiometricAuthenticator authenticator) {
 
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index afdc0c0..6ed1ac85 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -226,10 +226,6 @@
             return BIOMETRIC_NO_HARDWARE;
         }
 
-        if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
-            return BIOMETRIC_HARDWARE_NOT_DETECTED;
-        }
-
         final boolean wasStrongEnough =
                 Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
         final boolean isStrongEnough =
@@ -241,6 +237,10 @@
             return BIOMETRIC_INSUFFICIENT_STRENGTH;
         }
 
+        if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
+            return BIOMETRIC_HARDWARE_NOT_DETECTED;
+        }
+
         try {
             if (!sensor.impl.isHardwareDetected(opPackageName)) {
                 return BIOMETRIC_HARDWARE_NOT_DETECTED;
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index eeac260..6feae34 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -522,7 +522,7 @@
         // b/282922910 - we don't want apps sharing system uid and targeting
         // older target sdk to impact all system uid apps
         if (Flags.systemUidTargetSystemSdk() && !mIsWear &&
-                uid == Process.SYSTEM_UID) {
+                uid == Process.SYSTEM_UID && appInfo != null) {
             appInfo.targetSdkVersion = Build.VERSION.SDK_INT;
         }
         return appInfo;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5a2610b..abb756b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2460,6 +2460,15 @@
                 DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED);
     }
 
+    private void handleLogicalDisplayRefreshRateChangedLocked(@NonNull LogicalDisplay display) {
+        sendDisplayEventIfEnabledLocked(display,
+                DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED);
+    }
+
+    private void handleLogicalDisplayStateChangedLocked(@NonNull LogicalDisplay display) {
+        sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED);
+    }
+
     private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
         mDisplayModeDirector.defaultDisplayDeviceUpdated(display.getPrimaryDisplayDeviceLocked()
                 .mDisplayDeviceConfig);
@@ -3991,6 +4000,12 @@
                 case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED:
                     handleLogicalDisplayDisconnectedLocked(display);
                     break;
+                case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED:
+                    handleLogicalDisplayRefreshRateChangedLocked(display);
+                    break;
+                case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
+                    handleLogicalDisplayStateChangedLocked(display);
+                    break;
             }
         }
 
@@ -4198,6 +4213,13 @@
                     return (mask
                             & DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
                             != 0;
+                case DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+                    return (mask
+                            & DisplayManagerGlobal
+                            .INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0;
+                case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED:
+                    return (mask & DisplayManagerGlobal
+                            .INTERNAL_EVENT_FLAG_DISPLAY_STATE) != 0;
                 default:
                     // This should never happen.
                     Slog.e(TAG, "Unknown display event " + event);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 09fa4e6..c0903a9 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -79,15 +79,18 @@
     // 'adb shell setprop persist.log.tag.LogicalDisplayMapper DEBUG && adb reboot'
     private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
 
-    public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1;
-    public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2;
-    public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
-    public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 4;
-    public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 5;
-    public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 6;
-    public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 7;
-    public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 8;
-    public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 9;
+    public static final int LOGICAL_DISPLAY_EVENT_BASE = 0;
+    public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1 << 0;
+    public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 1 << 1;
+    public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 1 << 2;
+    public static final int LOGICAL_DISPLAY_EVENT_SWAPPED = 1 << 3;
+    public static final int LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED = 1 << 4;
+    public static final int LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION = 1 << 5;
+    public static final int LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED = 1 << 6;
+    public static final int LOGICAL_DISPLAY_EVENT_CONNECTED = 1 << 7;
+    public static final int LOGICAL_DISPLAY_EVENT_DISCONNECTED = 1 << 8;
+    public static final int LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED = 1 << 9;
+    public static final int LOGICAL_DISPLAY_EVENT_STATE_CHANGED = 1 << 10;
 
     public static final int DISPLAY_GROUP_EVENT_ADDED = 1;
     public static final int DISPLAY_GROUP_EVENT_CHANGED = 2;
@@ -804,6 +807,8 @@
             final boolean wasPreviouslyUpdated = updateState != UPDATE_STATE_NEW;
             final boolean wasPreviouslyEnabled = mDisplaysEnabledCache.get(displayId);
             final boolean isCurrentlyEnabled = display.isEnabledLocked();
+            int logicalDisplayEventMask = mLogicalDisplaysToUpdate
+                    .get(displayId, LOGICAL_DISPLAY_EVENT_BASE);
 
             // The display is no longer valid and needs to be removed.
             if (!display.isValidLocked()) {
@@ -821,20 +826,20 @@
                         if (mDisplaysEnabledCache.get(displayId)) {
                             // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED
                             reloop = true;
-                            mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
+                            logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED;
                         } else {
                             mUpdatedLogicalDisplays.delete(displayId);
-                            mLogicalDisplaysToUpdate.put(displayId,
-                                    LOGICAL_DISPLAY_EVENT_DISCONNECTED);
+                            logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DISCONNECTED;
                         }
                     } else {
                         mUpdatedLogicalDisplays.delete(displayId);
-                        mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
+                        logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED;
                     }
                 } else {
                     // This display never left this class, safe to remove without notification
                     mLogicalDisplays.removeAt(i);
                 }
+                mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask);
                 continue;
 
             // The display is new.
@@ -842,38 +847,40 @@
                 if (mFlags.isConnectedDisplayManagementEnabled()) {
                     // We still need to send LOGICAL_DISPLAY_EVENT_ADDED
                     reloop = true;
-                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CONNECTED);
+                    logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CONNECTED;
                 } else {
-                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);
+                    logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_ADDED;
                 }
             // Underlying displays device has changed to a different one.
             } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) {
-                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED);
+                logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_SWAPPED;
 
             // Something about the display device has changed.
             } else if (mFlags.isConnectedDisplayManagementEnabled()
                     && wasPreviouslyEnabled != isCurrentlyEnabled) {
                 int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED :
                         LOGICAL_DISPLAY_EVENT_REMOVED;
-                mLogicalDisplaysToUpdate.put(displayId, event);
+                logicalDisplayEventMask |= event;
             } else if (wasDirty || !mTempDisplayInfo.equals(newDisplayInfo)) {
                 // If only the hdr/sdr ratio changed, then send just the event for that case
                 if ((diff == DisplayDeviceInfo.DIFF_HDR_SDR_RATIO)) {
-                    mLogicalDisplaysToUpdate.put(displayId,
-                            LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED);
+                    logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED;
                 } else {
-                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+                    logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED;
                 }
 
-            // The display is involved in a display layout transition
+                if (mFlags.isDisplayListenerPerformanceImprovementsEnabled()) {
+                    logicalDisplayEventMask
+                            |= updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo);
+                }
+
+                // The display is involved in a display layout transition
             } else if (updateState == UPDATE_STATE_TRANSITION) {
-                mLogicalDisplaysToUpdate.put(displayId,
-                        LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
+                logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION;
 
             // Display frame rate overrides changed.
             } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
-                mLogicalDisplaysToUpdate.put(
-                        displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+                logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED;
 
             // Non-override display values changed.
             } else {
@@ -882,10 +889,10 @@
                 // things like display cutouts.
                 display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
                 if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
-                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+                    logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CHANGED;
                 }
             }
-
+            mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask);
             mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED);
         }
 
@@ -922,6 +929,8 @@
             sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED);
         }
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED);
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
         sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
         if (mFlags.isConnectedDisplayManagementEnabled()) {
@@ -944,13 +953,25 @@
         }
     }
 
+    @VisibleForTesting
+    int updateAndGetMaskForDisplayPropertyChanges(DisplayInfo newDisplayInfo) {
+        int mask = LOGICAL_DISPLAY_EVENT_BASE;
+        if (mTempDisplayInfo.getRefreshRate() != newDisplayInfo.getRefreshRate()) {
+            mask |= LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED;
+        }
+
+        if (mTempDisplayInfo.state != newDisplayInfo.state) {
+            mask |= LOGICAL_DISPLAY_EVENT_STATE_CHANGED;
+        }
+        return mask;
+    }
     /**
      * Send the specified message for all relevant displays in the specified display-to-message map.
      */
-    private void sendUpdatesForDisplaysLocked(int msg) {
+    private void sendUpdatesForDisplaysLocked(int logicalDisplayEvent) {
         for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) {
-            final int currMsg = mLogicalDisplaysToUpdate.valueAt(i);
-            if (currMsg != msg) {
+            final int logicalDisplayEventMask = mLogicalDisplaysToUpdate.valueAt(i);
+            if ((logicalDisplayEventMask & logicalDisplayEvent) == 0) {
                 continue;
             }
 
@@ -959,25 +980,25 @@
             if (DEBUG) {
                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
                 final String uniqueId = device == null ? "null" : device.getUniqueId();
-                Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id
-                        + " with device=" + uniqueId);
+                Slog.d(TAG, "Sending " + displayEventToString(logicalDisplayEvent) + " for "
+                        + "display=" + id + " with device=" + uniqueId);
             }
 
             if (mFlags.isConnectedDisplayManagementEnabled()) {
-                if (msg == LOGICAL_DISPLAY_EVENT_ADDED) {
+                if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_ADDED) {
                     mDisplaysEnabledCache.put(id, true);
-                } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
+                } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) {
                     mDisplaysEnabledCache.delete(id);
                 }
             }
 
-            mListener.onLogicalDisplayEventLocked(display, msg);
+            mListener.onLogicalDisplayEventLocked(display, logicalDisplayEvent);
 
             if (mFlags.isConnectedDisplayManagementEnabled()) {
-                if (msg == LOGICAL_DISPLAY_EVENT_DISCONNECTED) {
+                if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_DISCONNECTED) {
                     mLogicalDisplays.delete(id);
                 }
-            } else if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
+            } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) {
                 // We wait until we sent the EVENT_REMOVED event before actually removing the
                 // display.
                 mLogicalDisplays.delete(id);
@@ -1348,6 +1369,10 @@
                 return "connected";
             case LOGICAL_DISPLAY_EVENT_DISCONNECTED:
                 return "disconnected";
+            case LOGICAL_DISPLAY_EVENT_STATE_CHANGED:
+                return "state_changed";
+            case LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED:
+                return "refresh_rate_changed";
         }
         return null;
     }
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 9439eaa..9f0cabf 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1,5 +1,4 @@
 michaelwr@google.com
-dangittik@google.com
 hackbod@google.com
 ogunwale@google.com
 santoscordon@google.com
@@ -7,5 +6,6 @@
 wilczynskip@google.com
 brup@google.com
 petsjonkin@google.com
+olb@google.com
 
 per-file ColorDisplayService.java=christyfranks@google.com
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index 716661d..68dc80f 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -19,6 +19,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
 
@@ -29,23 +30,33 @@
      */
     private static final long TRANSITION_DURATION = 3000L;
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private ValueAnimator mAnimator;
+    @GuardedBy("mLock")
     private Boolean mIsActivated;
 
     public ValueAnimator getAnimator() {
-        return mAnimator;
+        synchronized (mLock) {
+            return mAnimator;
+        }
     }
 
     public void setAnimator(ValueAnimator animator) {
-        mAnimator = animator;
+        synchronized (mLock) {
+            mAnimator = animator;
+        }
     }
 
     /**
      * Cancel the animator if it's still running.
      */
     public void cancelAnimator() {
-        if (mAnimator != null) {
-            mAnimator.cancel();
+        synchronized (mLock) {
+            if (mAnimator != null) {
+                mAnimator.cancel();
+            }
         }
     }
 
@@ -53,22 +64,30 @@
      * End the animator if it's still running, jumping to the end state.
      */
     public void endAnimator() {
-        if (mAnimator != null) {
-            mAnimator.end();
-            mAnimator = null;
+        synchronized (mLock) {
+            if (mAnimator != null) {
+                mAnimator.end();
+                mAnimator = null;
+            }
         }
     }
 
     public void setActivated(Boolean isActivated) {
-        mIsActivated = isActivated;
+        synchronized (mLock) {
+            mIsActivated = isActivated;
+        }
     }
 
     public boolean isActivated() {
-        return mIsActivated != null && mIsActivated;
+        synchronized (mLock) {
+            return mIsActivated != null && mIsActivated;
+        }
     }
 
     public boolean isActivatedStateNotSet() {
-        return mIsActivated == null;
+        synchronized (mLock) {
+            return mIsActivated == null;
+        }
     }
 
     public long getTransitionDurationMilliseconds() {
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 71f17d1..1a7d74a 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -246,6 +246,10 @@
             Flags.FLAG_ENABLE_PLUGIN_MANAGER,
             Flags::enablePluginManager
     );
+    private final FlagState mDisplayListenerPerformanceImprovementsFlagState = new FlagState(
+            Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS,
+            Flags::displayListenerPerformanceImprovements
+    );
 
     /**
      * @return {@code true} if 'port' is allowed in display layout configuration file.
@@ -527,6 +531,13 @@
     }
 
     /**
+     * @return {@code true} if the flag for display listener performance improvements is enabled
+     */
+    public boolean isDisplayListenerPerformanceImprovementsEnabled() {
+        return mDisplayListenerPerformanceImprovementsFlagState.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
@@ -578,6 +589,7 @@
         pw.println(" " + mHasArrSupport);
         pw.println(" " + mAutoBrightnessModeBedtimeWearFlagState);
         pw.println(" " + mEnablePluginManagerFlagState);
+        pw.println(" " + mDisplayListenerPerformanceImprovementsFlagState);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 7850360..e7ea868 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -4,6 +4,14 @@
 # Important: Flags must be accessed through DisplayManagerFlags.
 
 flag {
+    name: "is_always_on_available_api"
+    namespace: "display_manager"
+    description: "Allows querying of AOD availability"
+    bug: "324046664"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_port_in_display_layout"
     namespace: "display_manager"
     description: "Allows refering to displays by port in display layout"
@@ -440,6 +448,14 @@
 }
 
 flag {
+    name: "display_listener_performance_improvements"
+    namespace: "display_manager"
+    description: "Feature flag for an API to let the apps subscribe to a specific property change of the Display."
+    bug: "372700957"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_get_supported_refresh_rates"
     namespace: "core_graphics"
     description: "Flag to use the surfaceflinger rates for getSupportedRefreshRates"
@@ -454,3 +470,11 @@
     bug: "354059797"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_display_content_mode_management"
+    namespace: "lse_desktop_experience"
+    description: "Enable switching the content mode of connected displays between mirroring and extened. Also change the default content mode to extended mode."
+    bug: "378385869"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
index 15f19cc..4a4c8da 100644
--- a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
+++ b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -28,12 +29,15 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 /**
  * SystemRequestObserver responsible for handling system requests to filter allowable display
  * modes
  */
 class SystemRequestObserver {
+    private static final String TAG = "SystemRequestObserver";
+
     private final VotesStorage mVotesStorage;
 
     private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@@ -43,6 +47,7 @@
         }
         @Override
         public void binderDied(@NonNull IBinder who) {
+            Slog.d(TAG, "binder died: " + who);
             removeSystemRequestedVotes(who);
             who.unlinkToDeath(mDeathRecipient, 0);
         }
@@ -83,9 +88,11 @@
                 updateStorageLocked(displayId);
             }
             if (needLinkToDeath) {
+                Slog.d(TAG, "binder linking to death: " + token);
                 token.linkToDeath(mDeathRecipient, 0);
             }
         } catch (RemoteException re) {
+            Slog.d(TAG, "linking to death failed: " + token, re);
             removeSystemRequestedVotes(token);
         }
     }
@@ -94,14 +101,19 @@
         boolean needToUnlink = false;
         synchronized (mLock) {
             SparseArray<List<Integer>> modesByDisplay = mDisplaysRestrictions.get(token);
-            if (modesByDisplay != null) {
+            if (modesByDisplay != null && modesByDisplay.size() > 0) {
                 modesByDisplay.remove(displayId);
                 needToUnlink = modesByDisplay.size() == 0;
                 updateStorageLocked(displayId);
             }
         }
         if (needToUnlink) {
-            token.unlinkToDeath(mDeathRecipient, 0);
+            try {
+                Slog.d(TAG, "binder unlinking to death: " + token);
+                token.unlinkToDeath(mDeathRecipient, 0);
+            } catch (NoSuchElementException e) {
+                Slog.d(TAG, "unlinking to death failed: " + token, e);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
index aef207f..f3820e5 100644
--- a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
+++ b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java
@@ -21,6 +21,7 @@
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.hardware.input.AppLaunchData;
 import android.hardware.input.InputGestureData;
@@ -137,11 +138,19 @@
                 String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
                 String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
                 String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);
-
-                // TODO(b/358569822): Shift bookmarks to use keycode instead of shortcutChar
-                int keycode = KeyEvent.KEYCODE_UNKNOWN;
                 String shortcut = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
-                if (!TextUtils.isEmpty(shortcut)) {
+                int keycode;
+                int modifierState;
+                TypedArray a = mContext.getResources().obtainAttributes(parser,
+                        R.styleable.Bookmark);
+                try {
+                    keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN);
+                    modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0);
+                } finally {
+                    a.recycle();
+                }
+                if (keycode == KeyEvent.KEYCODE_UNKNOWN && !TextUtils.isEmpty(shortcut)) {
+                    // Fetch keycode using shortcut char
                     KeyEvent[] events = virtualKcm.getEvents(new char[]{shortcut.toLowerCase(
                             Locale.ROOT).charAt(0)});
                     // Single key press can generate the character
@@ -153,12 +162,17 @@
                     Log.w(TAG, "Keycode required for bookmark with category=" + categoryName
                             + " packageName=" + packageName + " className=" + className
                             + " role=" + roleName + " shiftName=" + shiftName
-                            + " shortcut=" + shortcut);
+                            + " shortcut=" + shortcut + " modifierState=" + modifierState);
                     continue;
                 }
 
-                final boolean isShiftShortcut = (shiftName != null && shiftName.toLowerCase(
-                        Locale.ROOT).equals("true"));
+                if (modifierState == 0) {
+                    // Fetch modifierState using shiftName
+                    boolean isShiftShortcut = shiftName != null && shiftName.toLowerCase(
+                            Locale.ROOT).equals("true");
+                    modifierState =
+                            KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0);
+                }
                 AppLaunchData launchData = null;
                 if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
                     launchData = AppLaunchData.createLaunchDataForComponent(packageName, className);
@@ -168,11 +182,9 @@
                     launchData = AppLaunchData.createLaunchDataForRole(roleName);
                 }
                 if (launchData != null) {
-                    Log.d(TAG, "adding shortcut " + launchData + "shift="
-                            + isShiftShortcut + " keycode=" + keycode);
+                    Log.d(TAG, "adding shortcut " + launchData + " modifierState="
+                            + modifierState + " keycode=" + keycode);
                     // All bookmarks are based on Action key
-                    int modifierState =
-                            KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0);
                     InputGestureData bookmark = new InputGestureData.Builder()
                             .setTrigger(InputGestureData.createKeyTrigger(keycode, modifierState))
                             .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 6f35402..73d5630 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -228,6 +228,28 @@
                     KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                     KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK));
         }
+        if (enableTaskResizingKeyboardShortcuts()) {
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_LEFT_BRACKET,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_RIGHT_BRACKET,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_EQUALS,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW
+            ));
+            systemShortcuts.add(createKeyGesture(
+                    KeyEvent.KEYCODE_MINUS,
+                    KeyEvent.META_META_ON,
+                    KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW
+            ));
+        }
         if (keyboardA11yShortcutControl()) {
             if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
                 systemShortcuts.add(createKeyGesture(
@@ -257,28 +279,6 @@
                         KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS
                 ));
             }
-            if (enableTaskResizingKeyboardShortcuts()) {
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_LEFT_BRACKET,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_RIGHT_BRACKET,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_EQUALS,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW
-                ));
-                systemShortcuts.add(createKeyGesture(
-                        KeyEvent.KEYCODE_MINUS,
-                        KeyEvent.META_ALT_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE
-                ));
-            }
         }
         synchronized (mGestureLock) {
             for (InputGestureData systemShortcut : systemShortcuts) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f4dd717..edad247 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -193,7 +193,6 @@
     private DisplayManagerInternal mDisplayManagerInternal;
 
     private WindowManagerInternal mWindowManagerInternal;
-    private PackageManagerInternal mPackageManagerInternal;
 
     private final File mDoubleTouchGestureEnableFile;
 
@@ -573,7 +572,6 @@
 
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
 
         mSettingsObserver.registerAndUpdate();
 
@@ -623,9 +621,10 @@
         mKeyRemapper.systemRunning();
         mPointerIconCache.systemRunning();
         mKeyboardGlyphManager.systemRunning();
-        mKeyGestureController.systemRunning();
-
-        initKeyGestures();
+        if (useKeyGestureEventHandler()) {
+            mKeyGestureController.systemRunning();
+            initKeyGestures();
+        }
     }
 
     private void reloadDeviceAliases() {
@@ -2608,9 +2607,6 @@
     }
 
     private void initKeyGestures() {
-        if (!useKeyGestureEventHandler()) {
-            return;
-        }
         InputManager im = Objects.requireNonNull(mContext.getSystemService(InputManager.class));
         im.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
             @Override
@@ -2939,10 +2935,11 @@
     private void enforceManageKeyGesturePermission() {
         // TODO(b/361567988): Use @EnforcePermission to enforce permission once flag guarding the
         //  permission is rolled out
-        if (mSystemReady) {
-            String systemUIPackage = mContext.getString(R.string.config_systemUi);
-            int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal
-                    .getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
+        String systemUIPackage = mContext.getString(R.string.config_systemUi);
+        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+        if (pm != null) {
+            int systemUIAppId = UserHandle.getAppId(
+                    pm.getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
                             UserHandle.USER_SYSTEM));
             if (UserHandle.getCallingAppId() == systemUIAppId) {
                 return;
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index c3205af..0defd27 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -20,6 +20,7 @@
 import android.annotation.BinderThread;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.hardware.input.IKeyboardBacklightListener;
 import android.hardware.input.IKeyboardBacklightState;
@@ -81,9 +82,6 @@
     private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight";
 
     @VisibleForTesting
-    static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();
-
-    @VisibleForTesting
     static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL =
             new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1];
 
@@ -112,6 +110,7 @@
     private AmbientKeyboardBacklightController.AmbientKeyboardBacklightListener mAmbientListener;
 
     private int mAmbientBacklightValue = 0;
+    private final int mUserInactivityThresholdMs;
 
     static {
         // Fixed brightness levels to avoid issues when converting back and forth from the
@@ -139,6 +138,9 @@
         mAnimatorFactory = animatorFactory;
         mAmbientController = new AmbientKeyboardBacklightController(context, looper);
         mUEventManager = uEventManager;
+        Resources res = mContext.getResources();
+        mUserInactivityThresholdMs = res.getInteger(
+                com.android.internal.R.integer.config_keyboardBacklightTimeoutMs);
     }
 
     @Override
@@ -300,7 +302,7 @@
         }
         mHandler.removeMessages(MSG_NOTIFY_USER_INACTIVITY);
         mHandler.sendEmptyMessageAtTime(MSG_NOTIFY_USER_INACTIVITY,
-                SystemClock.uptimeMillis() + USER_INACTIVITY_THRESHOLD_MILLIS);
+                SystemClock.uptimeMillis() + mUserInactivityThresholdMs);
     }
 
     private void handleUserInactivity() {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java
new file mode 100644
index 0000000..c05f7a0
--- /dev/null
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java
@@ -0,0 +1,93 @@
+/*
+ * 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.server.location.contexthub;
+
+import android.hardware.contexthub.EndpointId;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IEndpointCallback;
+import android.hardware.contexthub.Message;
+import android.hardware.contexthub.MessageDeliveryStatus;
+import android.os.RemoteException;
+
+/** IEndpointCallback implementation. */
+public class ContextHubHalEndpointCallback
+        extends android.hardware.contexthub.IEndpointCallback.Stub {
+    private final IEndpointLifecycleCallback mEndpointLifecycleCallback;
+
+    /** Interface for listening for endpoint start and stop events. */
+    public interface IEndpointLifecycleCallback {
+        /** Called when a batch of endpoints started. */
+        void onEndpointStarted(HubEndpointInfo[] endpointInfos);
+
+        /** Called when a batch of endpoints stopped. */
+        void onEndpointStopped(HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason);
+    }
+
+    ContextHubHalEndpointCallback(IEndpointLifecycleCallback endpointLifecycleCallback) {
+        mEndpointLifecycleCallback = endpointLifecycleCallback;
+    }
+
+    @Override
+    public void onEndpointStarted(android.hardware.contexthub.EndpointInfo[] halEndpointInfos)
+            throws RemoteException {
+        if (halEndpointInfos.length == 0) {
+            return;
+        }
+        HubEndpointInfo[] endpointInfos = new HubEndpointInfo[halEndpointInfos.length];
+        for (int i = 0; i < halEndpointInfos.length; i++) {
+            endpointInfos[i++] = new HubEndpointInfo(halEndpointInfos[i]);
+        }
+        mEndpointLifecycleCallback.onEndpointStarted(endpointInfos);
+    }
+
+    @Override
+    public void onEndpointStopped(EndpointId[] halEndpointIds, byte reason) throws RemoteException {
+        HubEndpointInfo.HubEndpointIdentifier[] endpointIds =
+                new HubEndpointInfo.HubEndpointIdentifier[halEndpointIds.length];
+        for (int i = 0; i < halEndpointIds.length; i++) {
+            endpointIds[i] = new HubEndpointInfo.HubEndpointIdentifier(halEndpointIds[i]);
+        }
+        mEndpointLifecycleCallback.onEndpointStopped(endpointIds, reason);
+    }
+
+    @Override
+    public void onMessageReceived(int i, Message message) throws RemoteException {}
+
+    @Override
+    public void onMessageDeliveryStatusReceived(int i, MessageDeliveryStatus messageDeliveryStatus)
+            throws RemoteException {}
+
+    @Override
+    public void onEndpointSessionOpenRequest(
+            int i, EndpointId endpointId, EndpointId endpointId1, String s)
+            throws RemoteException {}
+
+    @Override
+    public void onCloseEndpointSession(int i, byte b) throws RemoteException {}
+
+    @Override
+    public void onEndpointSessionOpenComplete(int i) throws RemoteException {}
+
+    @Override
+    public int getInterfaceVersion() throws RemoteException {
+        return IEndpointCallback.VERSION;
+    }
+
+    @Override
+    public String getInterfaceHash() throws RemoteException {
+        return IEndpointCallback.HASH;
+    }
+}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index f611c57..8cf0578 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -31,6 +31,9 @@
 import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.contexthub.ErrorCode;
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.IContextHubEndpoint;
+import android.hardware.contexthub.IContextHubEndpointCallback;
 import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.location.ContextHubInfo;
 import android.hardware.location.ContextHubMessage;
@@ -249,6 +252,7 @@
         public void handleServiceRestart() {
             Log.i(TAG, "Recovering from Context Hub HAL restart...");
             initExistingCallbacks();
+            mHubInfoRegistry.onHalRestart();
             resetSettings();
             if (Flags.reconnectHostEndpointsAfterHalRestart()) {
                 mClientManager.forEachClientOfHub(mContextHubId,
@@ -330,6 +334,7 @@
         }
 
         initDefaultClientMap();
+        initEndpointCallback();
 
         initLocationSettingNotifications();
         initWifiSettingNotifications();
@@ -508,6 +513,18 @@
         mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
     }
 
+    private void initEndpointCallback() {
+        if (mHubInfoRegistry == null) {
+            return;
+        }
+        try {
+            mContextHubWrapper.registerEndpointCallback(
+                    new ContextHubHalEndpointCallback(mHubInfoRegistry));
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException while registering IEndpointCallback", e);
+        }
+    }
+
     /**
      * Initializes existing callbacks with the mContextHubWrapper for every context hub
      */
@@ -739,6 +756,26 @@
         return mHubInfoRegistry.getHubs();
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @Override
+    public List<HubEndpointInfo> findEndpoints(long endpointId) {
+        super.findEndpoints_enforcePermission();
+        if (mHubInfoRegistry == null) {
+            return Collections.emptyList();
+        }
+        return mHubInfoRegistry.findEndpoints(endpointId);
+    }
+
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @Override
+    public IContextHubEndpoint registerEndpoint(
+            HubEndpointInfo pendingHubEndpointInfo, IContextHubEndpointCallback callback)
+            throws RemoteException {
+        super.registerEndpoint_enforcePermission();
+        // TODO(b/375487784): Implement this
+        return null;
+    }
+
     /**
      * Creates an internal load transaction callback to be used for old API clients
      *
diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
index 68de9db..4d1000f 100644
--- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
+++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java
@@ -16,45 +16,144 @@
 
 package com.android.server.location.contexthub;
 
+import android.hardware.contexthub.HubEndpointInfo;
 import android.hardware.location.HubInfo;
 import android.os.RemoteException;
+import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-class HubInfoRegistry {
+class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback {
     private static final String TAG = "HubInfoRegistry";
+    private final Object mLock = new Object();
 
     private final IContextHubWrapper mContextHubWrapper;
 
-    private final List<HubInfo> mHubsInfo;
+    @GuardedBy("mLock")
+    private List<HubInfo> mHubsInfo;
+
+    @GuardedBy("mLock")
+    private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo>
+            mHubEndpointInfos = new ArrayMap<>();
 
     HubInfoRegistry(IContextHubWrapper contextHubWrapper) {
-        List<HubInfo> hubInfos;
         mContextHubWrapper = contextHubWrapper;
+        refreshCachedHubs();
+        refreshCachedEndpoints();
+    }
+
+    /** Retrieve the list of hubs available. */
+    List<HubInfo> getHubs() {
+        synchronized (mLock) {
+            return mHubsInfo;
+        }
+    }
+
+    private void refreshCachedHubs() {
+        List<HubInfo> hubInfos;
         try {
             hubInfos = mContextHubWrapper.getHubs();
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException while getting Hub info", e);
             hubInfos = Collections.emptyList();
         }
-        mHubsInfo = hubInfos;
+
+        synchronized (mLock) {
+            mHubsInfo = hubInfos;
+        }
     }
 
-    /** Retrieve the list of hubs available. */
-    List<HubInfo> getHubs() {
-        return mHubsInfo;
+    private void refreshCachedEndpoints() {
+        List<HubEndpointInfo> endpointInfos;
+        try {
+            endpointInfos = mContextHubWrapper.getEndpoints();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException while getting Hub info", e);
+            endpointInfos = Collections.emptyList();
+        }
+
+        synchronized (mLock) {
+            mHubEndpointInfos.clear();
+            for (HubEndpointInfo endpointInfo : endpointInfos) {
+                mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo);
+            }
+        }
+    }
+
+    /** Invoked when HAL restarts */
+    public void onHalRestart() {
+        synchronized (mLock) {
+            refreshCachedHubs();
+            refreshCachedEndpoints();
+        }
+    }
+
+    @Override
+    public void onEndpointStarted(HubEndpointInfo[] endpointInfos) {
+        synchronized (mLock) {
+            for (HubEndpointInfo endpointInfo : endpointInfos) {
+                mHubEndpointInfos.remove(endpointInfo.getIdentifier());
+                mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo);
+            }
+        }
+    }
+
+    @Override
+    public void onEndpointStopped(
+            HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) {
+        synchronized (mLock) {
+            for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) {
+                mHubEndpointInfos.remove(endpointId);
+            }
+        }
+    }
+
+    /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */
+    public List<HubEndpointInfo> findEndpoints(long endpointIdQuery) {
+        List<HubEndpointInfo> searchResult = new ArrayList<>();
+        synchronized (mLock) {
+            for (HubEndpointInfo.HubEndpointIdentifier endpointId : mHubEndpointInfos.keySet()) {
+                if (endpointId.getEndpoint() == endpointIdQuery) {
+                    searchResult.add(mHubEndpointInfos.get(endpointId));
+                }
+            }
+        }
+        return searchResult;
     }
 
     void dump(IndentingPrintWriter ipw) {
+        synchronized (mLock) {
+            dumpLocked(ipw);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void dumpLocked(IndentingPrintWriter ipw) {
         ipw.println(TAG);
 
         ipw.increaseIndent();
+        ipw.println("Hubs");
         for (HubInfo hubInfo : mHubsInfo) {
             ipw.println(hubInfo);
         }
         ipw.decreaseIndent();
+
+        ipw.println();
+
+        ipw.increaseIndent();
+        ipw.println("Endpoints");
+        for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) {
+            ipw.println(endpointInfo);
+        }
+        ipw.decreaseIndent();
+
+        ipw.println();
     }
+
 }
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 6656a6f..9b729eb 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.chre.flags.Flags;
 import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.HubEndpointInfo;
 import android.hardware.contexthub.MessageDeliveryStatus;
 import android.hardware.contexthub.NanSessionRequest;
 import android.hardware.contexthub.V1_0.ContextHub;
@@ -229,6 +230,15 @@
         return Collections.emptyList();
     }
 
+    /** Calls the appropriate getEndpoints function depending on the HAL version. */
+    public List<HubEndpointInfo> getEndpoints() throws RemoteException {
+        return Collections.emptyList();
+    }
+
+    /** Calls the appropriate registerEndpointCallback function depending on the HAL version. */
+    public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb)
+            throws RemoteException {}
+
     /**
      * @return True if this version of the Contexthub HAL supports Location setting notifications.
      */
@@ -622,6 +632,45 @@
             return retVal;
         }
 
+        @Override
+        public List<HubEndpointInfo> getEndpoints() throws RemoteException {
+            android.hardware.contexthub.IContextHub hub = getHub();
+            if (hub == null) {
+                return Collections.emptyList();
+            }
+
+            List<HubEndpointInfo> retVal = new ArrayList<>();
+            final List<android.hardware.contexthub.EndpointInfo> halEndpointInfos =
+                    hub.getEndpoints();
+            for (android.hardware.contexthub.EndpointInfo halEndpointInfo : halEndpointInfos) {
+                /* HAL -> API Type conversion */
+                final HubEndpointInfo endpointInfo = new HubEndpointInfo(halEndpointInfo);
+                if (DEBUG) {
+                    Log.i(TAG, "getEndpoints: endpointInfo=" + endpointInfo);
+                }
+                retVal.add(endpointInfo);
+            }
+
+            if (DEBUG) {
+                Log.i(TAG, "getEndpoints: total count=" + retVal.size());
+            }
+            return retVal;
+        }
+
+        @Override
+        public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb)
+                throws RemoteException {
+            android.hardware.contexthub.IContextHub hub = getHub();
+            if (hub == null) {
+                return;
+            }
+
+            if (DEBUG) {
+                Log.i(TAG, "registerEndpointCallback: cb=" + cb);
+            }
+            hub.registerEndpointCallback(cb);
+        }
+
         public boolean supportsLocationSettingNotifications() {
             return true;
         }
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
index c62e323..6536ca0 100644
--- a/services/core/java/com/android/server/location/contexthub/OWNERS
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -1,3 +1,4 @@
 bduddie@google.com
+arthuri@google.com
 matthewsedam@google.com
 stange@google.com
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 436acba..fce008c 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,7 +17,6 @@
 package com.android.server.media.projection;
 
 import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
-import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
 import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED;
 import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -28,7 +27,6 @@
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK;
 import static android.media.projection.ReviewGrantedConsentResult.UNKNOWN;
-import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -41,10 +39,7 @@
 import android.app.ActivityOptions.LaunchCookie;
 import android.app.AppOpsManager;
 import android.app.IProcessObserver;
-import android.app.KeyguardManager;
 import android.app.compat.CompatChanges;
-import android.app.role.RoleManager;
-import android.companion.AssociationRequest;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
@@ -74,7 +69,6 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.ContentRecordingSession;
@@ -85,7 +79,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.server.LocalServices;
-import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.wm.WindowManagerInternal;
@@ -140,12 +133,12 @@
     private final ActivityManagerInternal mActivityManagerInternal;
     private final PackageManager mPackageManager;
     private final WindowManagerInternal mWmInternal;
-    private final KeyguardManager mKeyguardManager;
-    private final RoleManager mRoleManager;
+
 
     private final MediaRouter mMediaRouter;
     private final MediaRouterCallback mMediaRouterCallback;
     private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
+    private final MediaProjectionStopController mMediaProjectionStopController;
     private MediaRouter.RouteInfo mMediaRouteInfo;
 
     @GuardedBy("mLock")
@@ -175,72 +168,16 @@
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
         mMediaRouterCallback = new MediaRouterCallback();
         mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger(context);
-        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mKeyguardManager.addKeyguardLockedStateListener(
-                mContext.getMainExecutor(), this::onKeyguardLockedStateChanged);
-        mRoleManager = mContext.getSystemService(RoleManager.class);
+        mMediaProjectionStopController = new MediaProjectionStopController(context,
+                this::maybeStopMediaProjection);
         Watchdog.getInstance().addMonitor(this);
     }
 
-    /**
-     * In order to record the keyguard, the MediaProjection package must be either:
-     *   - a holder of RECORD_SENSITIVE_CONTENT permission, or
-     *   - be one of the bugreport allowlisted packages, or
-     *   - hold the OP_PROJECT_MEDIA AppOp.
-     */
-    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
-    private boolean canCaptureKeyguard() {
-        if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
-            return true;
-        }
+    private void maybeStopMediaProjection(int reason) {
         synchronized (mLock) {
-            if (mProjectionGrant == null || mProjectionGrant.packageName == null) {
-                return false;
-            }
-            boolean disableScreenShareProtections = Settings.Global.getInt(
-                    getContext().getContentResolver(),
-                    DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0;
-            if (disableScreenShareProtections) {
-                Slog.v(TAG,
-                        "Allowing keyguard capture as screenshare protections are disabled.");
-                return true;
-            }
-
-            if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT,
-                    mProjectionGrant.packageName)
-                    == PackageManager.PERMISSION_GRANTED) {
-                Slog.v(TAG,
-                        "Allowing keyguard capture for package with RECORD_SENSITIVE_CONTENT "
-                                + "permission");
-                return true;
-            }
-            if (AppOpsManager.MODE_ALLOWED == mAppOps.noteOpNoThrow(AppOpsManager.OP_PROJECT_MEDIA,
-                    mProjectionGrant.uid, mProjectionGrant.packageName, /* attributionTag= */ null,
-                    "recording lockscreen")) {
-                // Some tools use media projection by granting the OP_PROJECT_MEDIA app
-                // op via a shell command. Those tools can be granted keyguard capture
-                Slog.v(TAG,
-                        "Allowing keyguard capture for package with OP_PROJECT_MEDIA AppOp ");
-                return true;
-            }
-            if (isProjectionAppHoldingAppStreamingRoleLocked()) {
-                Slog.v(TAG,
-                        "Allowing keyguard capture for package holding app streaming role.");
-                return true;
-            }
-            return SystemConfig.getInstance().getBugreportWhitelistedPackages()
-                    .contains(mProjectionGrant.packageName);
-        }
-    }
-
-    @VisibleForTesting
-    void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
-        if (!isKeyguardLocked) return;
-        synchronized (mLock) {
-            if (mProjectionGrant != null && !canCaptureKeyguard()
-                    && mProjectionGrant.mVirtualDisplayId != INVALID_DISPLAY) {
-                Slog.d(TAG, "Content Recording: Stopped MediaProjection"
-                        + " due to keyguard lock");
+            if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) {
+                Slog.d(TAG, "Content Recording: Stopping MediaProjection due to "
+                        + MediaProjectionStopController.stopReasonToString(reason));
                 mProjectionGrant.stop();
             }
         }
@@ -310,6 +247,8 @@
                 }
             });
         }
+
+        mMediaProjectionStopController.startTrackingStopReasons(mContext);
     }
 
     @Override
@@ -736,20 +675,6 @@
         }
     }
 
-    /**
-     * Application holding the app streaming role
-     * ({@value AssociationRequest#DEVICE_PROFILE_APP_STREAMING}) are allowed to record the
-     * lockscreen.
-     *
-     * @return true if the is held by the recording application.
-     */
-    @GuardedBy("mLock")
-    private boolean isProjectionAppHoldingAppStreamingRoleLocked() {
-        return mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
-                        mContext.getUser())
-                .contains(mProjectionGrant.packageName);
-    }
-
     private void dump(final PrintWriter pw) {
         pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)");
         synchronized (mLock) {
@@ -957,18 +882,19 @@
         public void requestConsentForInvalidProjection(@NonNull IMediaProjection projection) {
             requestConsentForInvalidProjection_enforcePermission();
 
-            if (android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()
-                    && mKeyguardManager.isKeyguardLocked()) {
-                Slog.v(TAG, "Reusing token: Won't request consent while the keyguard is locked");
-                return;
-            }
-
             synchronized (mLock) {
                 if (!isCurrentProjection(projection)) {
                     Slog.v(TAG, "Reusing token: Won't request consent again for a token that "
                             + "isn't current");
                     return;
                 }
+
+                if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) {
+                    Slog.v(TAG,
+                            "Reusing token: Won't request consent while MediaProjection is "
+                                    + "restricted");
+                    return;
+                }
             }
 
             // Remove calling app identity before performing any privileged operations.
@@ -1076,7 +1002,6 @@
         }
     }
 
-    @VisibleForTesting
     final class MediaProjection extends IMediaProjection.Stub {
         // Host app has 5 minutes to begin using the token before it is invalid.
         // Some apps show a dialog for the user to interact with (selecting recording resolution)
@@ -1347,6 +1272,10 @@
             return mDisplayId;
         }
 
+        long getCreateTimeMillis() {
+            return mCreateTimeMs;
+        }
+
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override
         public boolean isValid() {
@@ -1381,12 +1310,15 @@
         @Override
         public void notifyVirtualDisplayCreated(int displayId) {
             notifyVirtualDisplayCreated_enforcePermission();
-            if (mKeyguardManager.isKeyguardLocked() && !canCaptureKeyguard()) {
-                Slog.w(TAG, "Content Recording: Keyguard locked, aborting MediaProjection");
-                stop();
-                return;
-            }
             synchronized (mLock) {
+                if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) {
+                    Slog.w(TAG,
+                            "Content Recording: MediaProjection start disallowed, aborting "
+                                    + "MediaProjection");
+                    stop();
+                    return;
+                }
+
                 mVirtualDisplayId = displayId;
 
                 // If prior session was does not have a valid display id, then update the display
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java
new file mode 100644
index 0000000..c018e6b
--- /dev/null
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java
@@ -0,0 +1,239 @@
+/*
+ * 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.server.media.projection;
+
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
+import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
+
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.app.role.RoleManager;
+import android.companion.AssociationRequest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemConfig;
+
+import java.util.function.Consumer;
+
+/**
+ * Tracks events that should cause MediaProjection to stop
+ */
+public class MediaProjectionStopController {
+
+    private static final String TAG = "MediaProjectionStopController";
+    @VisibleForTesting
+    static final int STOP_REASON_UNKNOWN = 0;
+    @VisibleForTesting
+    static final int STOP_REASON_KEYGUARD = 1;
+    @VisibleForTesting
+    static final int STOP_REASON_CALL_END = 2;
+
+    private final TelephonyCallback mTelephonyCallback = new ProjectionTelephonyCallback();
+    private final Consumer<Integer> mStopReasonConsumer;
+    private final KeyguardManager mKeyguardManager;
+    private final TelecomManager mTelecomManager;
+    private final TelephonyManager mTelephonyManager;
+    private final AppOpsManager mAppOpsManager;
+    private final PackageManager mPackageManager;
+    private final RoleManager mRoleManager;
+    private final ContentResolver mContentResolver;
+
+    private boolean mIsInCall;
+    private long mLastCallStartTimeMillis;
+
+    public MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer) {
+        mStopReasonConsumer = stopReasonConsumer;
+        mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mTelecomManager = context.getSystemService(TelecomManager.class);
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+        mPackageManager = context.getPackageManager();
+        mRoleManager = context.getSystemService(RoleManager.class);
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * Start tracking stop reasons that may interrupt a MediaProjection session.
+     */
+    public void startTrackingStopReasons(Context context) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mKeyguardManager.addKeyguardLockedStateListener(context.getMainExecutor(),
+                    this::onKeyguardLockedStateChanged);
+            if (com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) {
+                callStateChanged();
+                mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(),
+                        mTelephonyCallback);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Checks whether the given projection grant is exempt from stopping restrictions.
+     */
+    public boolean isExemptFromStopping(
+            MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason) {
+        return isExempt(projectionGrant, stopReason, false);
+    }
+
+    /**
+     * Apps may disregard recording restrictions via MediaProjection for any stop reason if:
+     * - the "Disable Screenshare protections" developer option is enabled
+     * - the app is a holder of RECORD_SENSITIVE_CONTENT permission
+     * - the app holds the OP_PROJECT_MEDIA AppOp
+     * - the app holds the COMPANION_DEVICE_APP_STREAMING role
+     * - the app is one of the bugreport allowlisted packages
+     * - the current projection does not have an active VirtualDisplay associated with the
+     * MediaProjection session
+     */
+    private boolean isExempt(
+            MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason,
+            boolean forStart) {
+        if (projectionGrant == null || projectionGrant.packageName == null) {
+            return true;
+        }
+        boolean disableScreenShareProtections = Settings.Global.getInt(mContentResolver,
+                DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0;
+        if (disableScreenShareProtections) {
+            Slog.v(TAG, "Continuing MediaProjection as screenshare protections are disabled.");
+            return true;
+        }
+
+        if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT, projectionGrant.packageName)
+                == PackageManager.PERMISSION_GRANTED) {
+            Slog.v(TAG,
+                    "Continuing MediaProjection for package with RECORD_SENSITIVE_CONTENT "
+                            + "permission");
+            return true;
+        }
+        if (AppOpsManager.MODE_ALLOWED == mAppOpsManager.noteOpNoThrow(
+                AppOpsManager.OP_PROJECT_MEDIA, projectionGrant.uid,
+                projectionGrant.packageName, /* attributionTag= */ null, "recording lockscreen")) {
+            // Some tools use media projection by granting the OP_PROJECT_MEDIA app
+            // op via a shell command.
+            Slog.v(TAG, "Continuing MediaProjection for package with OP_PROJECT_MEDIA AppOp ");
+            return true;
+        }
+        if (mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
+                projectionGrant.userHandle).contains(projectionGrant.packageName)) {
+            Slog.v(TAG, "Continuing MediaProjection for package holding app streaming role.");
+            return true;
+        }
+        if (SystemConfig.getInstance().getBugreportWhitelistedPackages().contains(
+                projectionGrant.packageName)) {
+            Slog.v(TAG, "Continuing MediaProjection for package allowlisted for bugreporting.");
+            return true;
+        }
+        if (!forStart && projectionGrant.getVirtualDisplayId() == Display.INVALID_DISPLAY) {
+            Slog.v(TAG, "Continuing MediaProjection as current projection has no VirtualDisplay.");
+            return true;
+        }
+
+        if (stopReason == STOP_REASON_CALL_END
+                && projectionGrant.getCreateTimeMillis() < mLastCallStartTimeMillis) {
+            Slog.v(TAG,
+                    "Continuing MediaProjection as (phone) call started after MediaProjection was"
+                            + " created.");
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return {@code true} if a MediaProjection session is currently in a restricted state.
+     */
+    public boolean isStartForbidden(
+            MediaProjectionManagerService.MediaProjection projectionGrant) {
+        if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
+            return false;
+        }
+
+        if (!mKeyguardManager.isKeyguardLocked()) {
+            return false;
+        }
+
+        if (isExempt(projectionGrant, STOP_REASON_UNKNOWN, true)) {
+            return false;
+        }
+        return true;
+    }
+
+    @VisibleForTesting
+    void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+        if (!isKeyguardLocked) return;
+        if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) {
+            return;
+        }
+        mStopReasonConsumer.accept(STOP_REASON_KEYGUARD);
+    }
+
+    @VisibleForTesting
+    void callStateChanged() {
+        if (!com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) {
+            return;
+        }
+        boolean isInCall = mTelecomManager.isInCall();
+        if (isInCall) {
+            mLastCallStartTimeMillis = SystemClock.uptimeMillis();
+        }
+        if (isInCall == mIsInCall) {
+            return;
+        }
+
+        if (mIsInCall && !isInCall) {
+            mStopReasonConsumer.accept(STOP_REASON_CALL_END);
+        }
+        mIsInCall = isInCall;
+    }
+
+    /**
+     * @return a String representation of the stop reason interrupting MediaProjection.
+     */
+    public static String stopReasonToString(int stopReason) {
+        switch (stopReason) {
+            case STOP_REASON_KEYGUARD -> {
+                return "STOP_REASON_KEYGUARD";
+            }
+            case STOP_REASON_CALL_END -> {
+                return "STOP_REASON_CALL_END";
+            }
+        }
+        return "";
+    }
+
+    private final class ProjectionTelephonyCallback extends TelephonyCallback implements
+            TelephonyCallback.CallStateListener {
+        @Override
+        public void onCallStateChanged(int state) {
+            callStateChanged();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 84413d5..1f8a200 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -96,7 +96,35 @@
 
         @Override
         public PictureProfile getPictureProfile(int type, String name) {
-            return null;
+            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+            String selection = PictureQuality.PARAMETER_TYPE + " = ? AND "
+                    + PictureQuality.PARAMETER_NAME + " = ?";
+            String[] selectionArguments = {Integer.toString(type), name};
+
+            try (
+                    Cursor cursor = db.query(
+                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                            getAllPictureProfileColumns(),
+                            selection,
+                            selectionArguments,
+                            /*groupBy=*/ null,
+                            /*having=*/ null,
+                            /*orderBy=*/ null)
+            ) {
+                int count = cursor.getCount();
+                if (count == 0) {
+                    return null;
+                }
+                if (count > 1) {
+                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s"
+                                    + " in %s. Should only ever be 0 or 1.", count, type, name,
+                                    mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+                    return null;
+                }
+                cursor.moveToFirst();
+                return getPictureProfileFromCursor(cursor);
+            }
         }
 
         private String bundleToJson(Bundle bundle) {
@@ -145,17 +173,79 @@
             return bundle;
         }
 
+        private String[] getAllPictureProfileColumns() {
+            return new String[]{
+                    PictureQuality.PARAMETER_ID,
+                    PictureQuality.PARAMETER_TYPE,
+                    PictureQuality.PARAMETER_NAME,
+                    PictureQuality.PARAMETER_INPUT_ID,
+                    PictureQuality.PARAMETER_PACKAGE,
+                    mMediaQualityDbHelper.SETTINGS
+            };
+        }
+
+        private PictureProfile getPictureProfileFromCursor(Cursor cursor) {
+            String returnId = cursor.getString(
+                    cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_ID));
+            int type = cursor.getInt(
+                    cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_TYPE));
+            String name = cursor.getString(
+                    cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_NAME));
+            String inputId = cursor.getString(
+                    cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_INPUT_ID));
+            String packageName = cursor.getString(
+                    cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_PACKAGE));
+            String settings = cursor.getString(
+                    cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
+            return new PictureProfile(returnId, type, name, inputId,
+                    packageName, jsonToBundle(settings));
+        }
+
         @Override
         public List<PictureProfile> getPictureProfilesByPackage(String packageName) {
-            return new ArrayList<>();
+            String selection = PictureQuality.PARAMETER_PACKAGE + " = ?";
+            String[] selectionArguments = {packageName};
+            return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
+                    selectionArguments);
         }
+
         @Override
         public List<PictureProfile> getAvailablePictureProfiles() {
             return new ArrayList<>();
         }
+
         @Override
         public List<String> getPictureProfilePackageNames() {
-            return new ArrayList<>();
+            String [] column = {PictureQuality.PARAMETER_NAME};
+            List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
+                    null, null);
+            List<String> packageNames = new ArrayList<>();
+            for (PictureProfile pictureProfile: pictureProfiles) {
+                packageNames.add(pictureProfile.getName());
+            }
+            return packageNames;
+        }
+
+        private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns,
+                String selection, String[] selectionArguments) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+
+            try (
+                    Cursor cursor = db.query(
+                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                            columns,
+                            selection,
+                            selectionArguments,
+                            /*groupBy=*/ null,
+                            /*having=*/ null,
+                            /*orderBy=*/ null)
+            ) {
+                List<PictureProfile> pictureProfiles = new ArrayList<>();
+                while (cursor.moveToNext()) {
+                    pictureProfiles.add(getPictureProfileFromCursor(cursor));
+                }
+                return pictureProfiles;
+            }
         }
 
         @Override
@@ -172,7 +262,7 @@
             // TODO: implement
         }
         @Override
-        public SoundProfile getSoundProfileById(String id) {
+        public SoundProfile getSoundProfile(int type, String id) {
             return null;
         }
         @Override
@@ -223,6 +313,15 @@
         }
 
         @Override
+        public List<String> getSoundProfileAllowList() {
+            return new ArrayList<>();
+        }
+
+        @Override
+        public void setSoundProfileAllowList(List<String> packages) {
+        }
+
+        @Override
         public boolean isSupported() {
             return false;
         }
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 5914dbe..7fd9620 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -92,10 +92,16 @@
     static final int REGROUP_REASON_CHANNEL_UPDATE = 0;
     // Regrouping needed because of notification bundling
     static final int REGROUP_REASON_BUNDLE = 1;
+    // Regrouping needed because of notification unbundling
+    static final int REGROUP_REASON_UNBUNDLE = 2;
+    // Regrouping needed because of notification unbundling + the original group summary exists
+    static final int REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP = 3;
 
     @IntDef(prefix = { "REGROUP_REASON_" }, value = {
         REGROUP_REASON_CHANNEL_UPDATE,
         REGROUP_REASON_BUNDLE,
+        REGROUP_REASON_UNBUNDLE,
+        REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface RegroupingReason {}
@@ -103,7 +109,6 @@
     private final Callback mCallback;
     private final int mAutoGroupAtCount;
     private final int mAutogroupSparseGroupsAtCount;
-    private final int mAutoGroupRegroupingAtCount;
     private final Context mContext;
     private final PackageManager mPackageManager;
     private boolean mIsTestHarnessExempted;
@@ -190,11 +195,6 @@
         mContext = context;
         mPackageManager = packageManager;
         mAutogroupSparseGroupsAtCount = autoGroupSparseGroupsAtCount;
-        if (notificationRegroupOnClassification()) {
-            mAutoGroupRegroupingAtCount = 1;
-        } else {
-            mAutoGroupRegroupingAtCount = mAutoGroupAtCount;
-        }
         NOTIFICATION_SHADE_SECTIONS = getNotificationShadeSections();
     }
 
@@ -797,7 +797,8 @@
                         Slog.v(TAG, "isGroupChildInDifferentBundleThanSummary: " + record);
                     }
                     moveNotificationsToNewSection(record.getUserId(), pkgName,
-                            List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey)));
+                            List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey)),
+                            REGROUP_REASON_BUNDLE);
                     return;
                 }
             }
@@ -945,6 +946,27 @@
         }
     }
 
+    /**
+     * Called when a notification that was classified (bundled) is restored to its original channel.
+     * The notification will be restored to its original group, if any/if summary still exists.
+     * Otherwise it will be moved to the appropriate section as an ungrouped notification.
+     *
+     * @param record the notification which had its channel updated
+     * @param originalSummaryExists the original group summary exists
+     */
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING)
+    public void onNotificationUnbundled(final NotificationRecord record,
+            final boolean originalSummaryExists) {
+        synchronized (mAggregatedNotifications) {
+            ArrayMap<String, NotificationRecord> notificationsToCheck = new ArrayMap<>();
+            notificationsToCheck.put(record.getKey(), record);
+            regroupNotifications(record.getUserId(), record.getSbn().getPackageName(),
+                    notificationsToCheck,
+                    originalSummaryExists ? REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP
+                        : REGROUP_REASON_UNBUNDLE);
+        }
+    }
+
     @GuardedBy("mAggregatedNotifications")
     private void regroupNotifications(int userId, String pkgName,
             ArrayMap<String, NotificationRecord> notificationsToCheck,
@@ -973,7 +995,7 @@
 
         // Batch move to new section
         if (!notificationsToMove.isEmpty()) {
-            moveNotificationsToNewSection(userId, pkgName, notificationsToMove);
+            moveNotificationsToNewSection(userId, pkgName, notificationsToMove, regroupingReason);
         }
     }
 
@@ -1093,7 +1115,7 @@
 
     @GuardedBy("mAggregatedNotifications")
     private void moveNotificationsToNewSection(final int userId, final String pkgName,
-            final List<NotificationMoveOp> notificationsToMove) {
+            final List<NotificationMoveOp> notificationsToMove, int regroupingReason) {
         record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record,
                              boolean hasSummary) { }
         // Bundled operations to apply to groups affected by the channel update
@@ -1111,7 +1133,8 @@
             if (DEBUG) {
                 Log.i(TAG,
                     "moveNotificationToNewSection: " + record + " " + newFullAggregateGroupKey
-                        + " from: " + oldFullAggregateGroupKey);
+                            + " from: " + oldFullAggregateGroupKey + " regroupingReason: "
+                            + regroupingReason);
             }
 
             // Update/remove aggregate summary for old group
@@ -1140,28 +1163,35 @@
             // Add moved notifications to the ungrouped list for new group and do grouping
             // after all notifications have been handled
             if (newFullAggregateGroupKey != null) {
-                final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs =
+                if (notificationRegroupOnClassification()
+                        && regroupingReason == REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP) {
+                    // Just reset override group key, original summary exists
+                    // => will be grouped back to its original group
+                    record.setOverrideGroupKey(null);
+                } else {
+                    final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs =
                         mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey,
                             new ArrayMap<>());
-                boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty();
-                ArrayMap<String, NotificationAttributes> ungrouped =
+                    boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty();
+                    ArrayMap<String, NotificationAttributes> ungrouped =
                         mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey,
                             new ArrayMap<>());
-                ungrouped.put(record.getKey(), new NotificationAttributes(
+                    ungrouped.put(record.getKey(), new NotificationAttributes(
                         record.getFlags(),
                         record.getNotification().getSmallIcon(),
                         record.getNotification().color,
                         record.getNotification().visibility,
                         record.getNotification().getGroupAlertBehavior(),
                         record.getChannel().getId()));
-                mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped);
+                    mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped);
 
-                record.setOverrideGroupKey(null);
+                    record.setOverrideGroupKey(null);
 
-                // Only add once, for triggering notification
-                if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) {
-                    groupsToUpdate.put(newFullAggregateGroupKey,
-                        new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary));
+                    // Only add once, for triggering notification
+                    if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) {
+                        groupsToUpdate.put(newFullAggregateGroupKey,
+                            new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary));
+                    }
                 }
             }
         }
@@ -1176,7 +1206,7 @@
             NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record;
             boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary;
             //Group needs to be created/updated
-            if (ungrouped.size() >= mAutoGroupRegroupingAtCount
+            if (ungrouped.size() >= mAutoGroupAtCount
                     || (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) {
                 NotificationSectioner sectioner = getSection(triggeringNotification);
                 if (sectioner == null) {
@@ -1436,7 +1466,8 @@
         }
     }
 
-    private ArrayMap<String, NotificationRecord> getSparseGroups(
+    @VisibleForTesting
+    protected ArrayMap<String, NotificationRecord> getSparseGroups(
             final FullyQualifiedGroupKey fullAggregateGroupKey,
             final List<NotificationRecord> notificationList,
             final Map<String, NotificationRecord> summaryByGroupKey,
@@ -1448,8 +1479,8 @@
                         && summary.getUserId() == fullAggregateGroupKey.userId
                         && summary.getSbn().isAppGroup()
                         && !summary.getGroupKey().equals(fullAggregateGroupKey.toString())) {
-                    int numChildren = getNumChildrenForGroup(summary.getSbn().getGroup(),
-                            notificationList);
+                    int numChildren = getNumChildrenForGroupWithSection(summary.getSbn().getGroup(),
+                            notificationList, sectioner);
                     if (numChildren > 0 && numChildren < MIN_CHILD_COUNT_TO_AVOID_FORCE_GROUPING) {
                         sparseGroups.put(summary.getGroupKey(), summary);
                     }
@@ -1459,6 +1490,43 @@
         return sparseGroups;
     }
 
+    /**
+     *  Get the number of children of a group if all match a certain section.
+     *  Used for force grouping sparse groups, where the summary may match a section but the
+     *  child notifications do not: ie. conversations
+     *
+     * @param groupKey the group key (name)
+     * @param notificationList all notifications list
+     * @param sectioner the section to match
+     * @return number of children in that group or -1 if section does not match
+     */
+    private int getNumChildrenForGroupWithSection(final String groupKey,
+            final List<NotificationRecord> notificationList,
+            final NotificationSectioner sectioner) {
+        int numChildren = 0;
+        for (NotificationRecord r : notificationList) {
+            if (!r.getNotification().isGroupSummary() && groupKey.equals(r.getSbn().getGroup())) {
+                NotificationSectioner childSection = getSection(r);
+                if (childSection == null || childSection != sectioner) {
+                    if (DEBUG) {
+                        Slog.i(TAG,
+                                "getNumChildrenForGroupWithSection skip because invalid section: "
+                                    + groupKey + " r: " + r);
+                    }
+                    return -1;
+                } else {
+                    numChildren++;
+                }
+            }
+        }
+
+        if (DEBUG) {
+            Slog.i(TAG,
+                    "getNumChildrenForGroupWithSection " + groupKey + " numChild: " + numChildren);
+        }
+        return numChildren;
+    }
+
     @GuardedBy("mAggregatedNotifications")
     private void cacheCanceledSummary(NotificationRecord record) {
         final FullyQualifiedGroupKey groupKey = new FullyQualifiedGroupKey(record.getUserId(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index d5d4070..52ddb80 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -22,8 +22,11 @@
 import android.app.backup.BackupRestoreEventLogger;
 import android.service.notification.DeviceEffectsApplier;
 
+import com.android.internal.annotations.Keep;
+
 import java.util.Set;
 
+@Keep
 public interface NotificationManagerInternal {
     NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
     NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4d0c7ec..5182dfe 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -211,6 +211,7 @@
 import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException;
 import android.app.StatsManager;
 import android.app.UriGrantsManager;
+import android.app.ZenBypassingApp;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.backup.BackupManager;
 import android.app.backup.BackupRestoreEventLogger;
@@ -238,7 +239,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.LauncherApps;
 import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
@@ -3089,7 +3089,7 @@
             migrateDefaultNAS();
             maybeShowInitialReviewPermissionsNotification();
 
-            if (android.app.Flags.modesApi()) {
+            if (android.app.Flags.modesApi() && !mZenModeHelper.hasDeviceEffectsApplier()) {
                 // Cannot be done earlier, as some services aren't ready until this point.
                 mZenModeHelper.setDeviceEffectsApplier(
                         new DefaultDeviceEffectsApplier(getContext()));
@@ -4043,7 +4043,7 @@
                         "canNotifyAsPackage for uid " + uid);
             }
 
-            return areNotificationsEnabledForPackageInt(pkg, uid);
+            return areNotificationsEnabledForPackageInt(uid);
         }
 
         /**
@@ -4864,30 +4864,20 @@
         }
 
         @Override
-        public List<String> getPackagesBypassingDnd(int userId,
-                boolean includeConversationChannels) {
+        public ParceledListSlice<ZenBypassingApp> getPackagesBypassingDnd(int userId)
+                throws RemoteException {
             checkCallerIsSystem();
 
-            final ArraySet<String> packageNames = new ArraySet<>();
-
-            List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, userId);
-            for (PackageInfo pi : pkgs) {
-                String pkg = pi.packageName;
-                // If any NotificationChannel for this package is bypassing, the
-                // package is considered bypassing.
-                for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg,
-                        pi.applicationInfo.uid).getList()) {
-                    // Skips non-demoted conversation channels.
-                    if (!includeConversationChannels
-                            && !TextUtils.isEmpty(channel.getConversationId())
-                            && !channel.isDemoted()) {
-                        continue;
-                    }
-                    packageNames.add(pkg);
+            UserHandle user = UserHandle.of(userId);
+            ArrayList<ZenBypassingApp> bypassing =
+                    mPreferencesHelper.getPackagesBypassingDnd(userId);
+            for (int i = bypassing.size() - 1; i >= 0; i--) {
+                String pkg = bypassing.get(i).getPkg();
+                if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) {
+                    bypassing.remove(i);
                 }
             }
-
-            return new ArrayList<String>(packageNames);
+            return new ParceledListSlice<>(bypassing);
         }
 
         @Override
@@ -7190,13 +7180,16 @@
                         Slog.i(TAG, "Removing app summary (all children bundled): "
                                 + groupSummary);
                     }
-                    canceledSummary = groupSummary;
-                    mSummaryByGroupKey.remove(oldGroupKey);
-                    cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(),
+                    if (convertSummaryToNotificationLocked(groupSummary.getKey())) {
+                        groupSummary.isCanceled = true;
+                        canceledSummary = groupSummary;
+                        mSummaryByGroupKey.remove(oldGroupKey);
+                        cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(),
                             groupSummary.getSbn().getPackageName(),
                             groupSummary.getSbn().getTag(),
                             groupSummary.getSbn().getId(), 0, 0, false, groupSummary.getUserId(),
                             NotificationListenerService.REASON_GROUP_OPTIMIZATION, null);
+                    }
                 }
             }
         }
@@ -7763,7 +7756,7 @@
 
         @Override
         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
-            return areNotificationsEnabledForPackageInt(pkg, uid);
+            return areNotificationsEnabledForPackageInt(uid);
         }
 
         @Override
@@ -8742,7 +8735,7 @@
         }
 
         // blocked apps
-        boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
+        boolean isBlocked = !areNotificationsEnabledForPackageInt(uid);
         synchronized (mNotificationLock) {
             isBlocked |= isRecordBlockedLocked(r);
         }
@@ -8792,7 +8785,7 @@
         }
     }
 
-    private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
+    private boolean areNotificationsEnabledForPackageInt(int uid) {
         return mPermissionHelper.hasPermission(uid);
     }
 
@@ -9328,7 +9321,7 @@
          * notifying all listeners to a background thread; false otherwise.
          */
         private boolean postNotification() {
-            boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
+            boolean appBanned = !areNotificationsEnabledForPackageInt(uid);
             boolean isCallNotification = isCallNotification(pkg, uid);
             boolean posted = false;
             synchronized (NotificationManagerService.this.mNotificationLock) {
@@ -11947,16 +11940,19 @@
                     TrimCache trimCache = new TrimCache(sbn);
                     final INotificationListener assistant = (INotificationListener) info.service;
                     final StatusBarNotification sbnToPost = trimCache.ForListener(info);
-                    final StatusBarNotificationHolder sbnHolder =
-                            new StatusBarNotificationHolder(sbnToPost);
+                    final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
+
                     try {
-                        if (debug) {
-                            Slog.v(TAG,
-                                    "calling onNotificationEnqueuedWithChannel " + sbnHolder);
+                        if (android.app.Flags.noSbnholder()) {
+                            assistant.onNotificationEnqueuedWithChannelFull(sbnToPost,
+                                    r.getChannel(), update);
+                        } else {
+                            final StatusBarNotificationHolder sbnHolder =
+                                    new StatusBarNotificationHolder(sbnToPost);
+
+                            assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
+                                    update);
                         }
-                        final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
-                        assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel(),
-                                update);
                     } catch (RemoteException ex) {
                         Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
                     }
@@ -11976,7 +11972,7 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onNotificationVisibilityChanged(key, isVisible);
                         } catch (RemoteException ex) {
@@ -11996,7 +11992,7 @@
                     sbn,
                     notificationType,
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
                         } catch (RemoteException ex) {
@@ -12013,7 +12009,7 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onNotificationDirectReply(key);
                         } catch (RemoteException ex) {
@@ -12031,7 +12027,7 @@
                     sbn,
                     notificationType,
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onSuggestedReplySent(
                                     key,
@@ -12054,7 +12050,7 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onActionClicked(
                                     key,
@@ -12079,10 +12075,17 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, sbnToPost) -> {
                         try {
-                            assistant.onNotificationSnoozedUntilContext(
-                                    sbnHolder, snoozeCriterionId);
+                            if (android.app.Flags.noSbnholder()) {
+                                assistant.onNotificationSnoozedUntilContextFull(
+                                        sbnToPost, snoozeCriterionId);
+                            } else {
+                                final StatusBarNotificationHolder sbnHolder =
+                                        new StatusBarNotificationHolder(sbnToPost);
+                                assistant.onNotificationSnoozedUntilContext(
+                                        sbnHolder, snoozeCriterionId);
+                            }
                         } catch (RemoteException ex) {
                             Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
                         }
@@ -12096,7 +12099,7 @@
                     r.getSbn(),
                     r.getNotificationType(),
                     true /* sameUserOnly */,
-                    (assistant, sbnHolder) -> {
+                    (assistant, unused) -> {
                         try {
                             assistant.onNotificationClicked(key);
                         } catch (RemoteException ex) {
@@ -12139,7 +12142,7 @@
                 final StatusBarNotification sbn,
                 int notificationType,
                 boolean sameUserOnly,
-                BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
+                BiConsumer<INotificationListener, StatusBarNotification> callback) {
             TrimCache trimCache = new TrimCache(sbn);
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
@@ -12161,9 +12164,7 @@
                 }
                 final INotificationListener assistant = (INotificationListener) info.service;
                 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
-                final StatusBarNotificationHolder sbnHolder =
-                        new StatusBarNotificationHolder(sbnToPost);
-                mHandler.post(() -> callback.accept(assistant, sbnHolder));
+                mHandler.post(() -> callback.accept(assistant, sbnToPost));
             }
         }
 
@@ -13409,9 +13410,13 @@
         private void notifyPosted(final ManagedServiceInfo info,
                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
             final INotificationListener listener = (INotificationListener) info.service;
-            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
-                listener.onNotificationPosted(sbnHolder, rankingUpdate);
+                if (android.app.Flags.noSbnholder()) {
+                    listener.onNotificationPostedFull(sbn, rankingUpdate);
+                } else {
+                    StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
+                    listener.onNotificationPosted(sbnHolder, rankingUpdate);
+                }
             } catch (DeadObjectException ex) {
                 Slog.wtf(TAG, "unable to notify listener (posted): " + info, ex);
             } catch (RemoteException ex) {
@@ -13422,7 +13427,6 @@
         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
                 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
             final INotificationListener listener = (INotificationListener) info.service;
-            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
             try {
                 if (!CompatChanges.isChangeEnabled(NOTIFICATION_CANCELLATION_REASONS, info.uid)
                         && (reason == REASON_CHANNEL_REMOVED || reason == REASON_CLEAR_DATA)) {
@@ -13434,7 +13438,12 @@
                         && reason == REASON_ASSISTANT_CANCEL) {
                     reason = REASON_LISTENER_CANCEL;
                 }
-                listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+                if (android.app.Flags.noSbnholder()) {
+                    listener.onNotificationRemovedFull(sbn, rankingUpdate, stats, reason);
+                } else {
+                    StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
+                    listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
+                }
             } catch (DeadObjectException ex) {
                 Slog.wtf(TAG, "unable to notify listener (removed): " + info, ex);
             } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9f0b4b0..e6f784c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -57,6 +57,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.app.NotificationManager;
+import android.app.ZenBypassingApp;
 import android.content.AttributionSource;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -1950,6 +1951,35 @@
     }
 
     /**
+     * Gets all apps that can bypass DND, and a boolean indicating whether all (true) or some
+     * (false) of its notification channels can currently bypass.
+     */
+    public @NonNull ArrayList<ZenBypassingApp> getPackagesBypassingDnd(@UserIdInt int userId) {
+        ArrayList<ZenBypassingApp> bypassing = new ArrayList<>();
+        synchronized (mLock) {
+            for (PackagePreferences p : mPackagePreferences.values()) {
+                if (p.userId != userId) {
+                    continue;
+                }
+                int totalChannelCount = p.channels.size();
+                int bypassingCount = 0;
+                if  (totalChannelCount == 0) {
+                    continue;
+                }
+                for (NotificationChannel channel : p.channels.values()) {
+                    if (channelIsLiveLocked(p, channel) && channel.canBypassDnd()) {
+                        bypassingCount++;
+                    }
+                }
+                if (bypassingCount > 0) {
+                    bypassing.add(new ZenBypassingApp(p.pkg, totalChannelCount == bypassingCount));
+                }
+            }
+        }
+        return bypassing;
+    }
+
+    /**
      * True for pre-O apps that only have the default channel, or pre O apps that have no
      * channels yet. This method will create the default channel for pre-O apps that don't have it.
      * Should never be true for O+ targeting apps, but that's enforced on boot/when an app
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index cfeacdf..81dc38a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -24,6 +24,8 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
+import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING;
 import static android.service.notification.Condition.SOURCE_UNKNOWN;
 import static android.service.notification.Condition.SOURCE_USER_ACTION;
 import static android.service.notification.Condition.STATE_FALSE;
@@ -44,8 +46,6 @@
 
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.internal.util.Preconditions.checkArgument;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
-import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING;
 
 import static java.util.Objects.requireNonNull;
 
@@ -303,6 +303,15 @@
     }
 
     /**
+     * @return whether a {@link DeviceEffectsApplier} has already been set or not
+     */
+    boolean hasDeviceEffectsApplier() {
+        synchronized (mConfigLock) {
+            return mDeviceEffectsApplier != null;
+        }
+    }
+
+    /**
      * Set the {@link DeviceEffectsApplier} used to apply the consolidated effects.
      *
      * <p>Previously calculated effects (as loaded from the user's {@link ZenModeConfig}) will be
@@ -1006,7 +1015,13 @@
     private static void applyConditionAndReconsiderOverride(ZenRule rule, Condition condition,
             int origin) {
         if (Flags.modesApi() && Flags.modesUi()) {
-            if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null
+            if (isImplicitRuleId(rule.id)) {
+                // Implicit rules do not use overrides, and always apply conditions directly.
+                // This is compatible with the previous behavior (where the package set the
+                // interruption filter, and no "snoozing" took place if the user changed it later).
+                rule.condition = condition;
+                rule.resetConditionOverride();
+            } else if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null
                     && condition.source == SOURCE_USER_ACTION) {
                 // Apply as override, instead of actual condition.
                 // If the new override is the reverse of a previous (still active) override, try
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 9f4b9f1..6d54be8 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -58,6 +58,7 @@
 import android.os.storage.VolumeInfo;
 import android.provider.DeviceConfig;
 import android.stats.storage.StorageEnums;
+import android.text.TextUtils;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
@@ -355,7 +356,8 @@
             @Nullable int[] userIds,
             @Nullable int[] instantUserIds,
             @Nullable SparseArray<int[]> broadcastAllowList,
-            @NonNull AndroidPackage pkg) {
+            @NonNull AndroidPackage pkg,
+            @NonNull String[] sharedUidPackages) {
         final boolean isForWholeApp = componentNames.contains(packageName);
         if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) {
             sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames,
@@ -374,20 +376,36 @@
         exportedComponentNames.removeAll(notExportedComponentNames);
 
         if (!notExportedComponentNames.isEmpty()) {
-            // Limit sending of the PACKAGE_CHANGED broadcast to only the system and the
-            // application itself when the component is not exported.
+            // Limit sending of the PACKAGE_CHANGED broadcast to only the system, the application
+            // itself and applications with the same UID when the component is not exported.
 
             // First, send the PACKAGE_CHANGED broadcast to the system.
-            sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
-                    notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
-                    broadcastAllowList, "android" /* targetPackageName */,
-                    new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+            if (!TextUtils.equals(packageName, "android")) {
+                sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
+                        notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
+                        broadcastAllowList, "android" /* targetPackageName */,
+                        new String[]{
+                                PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+            }
 
             // Second, send the PACKAGE_CHANGED broadcast to the application itself.
             sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
                     notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
                     broadcastAllowList, packageName /* targetPackageName */,
                     null /* requiredPermissions */);
+
+            // Third, send the PACKAGE_CHANGED broadcast to the applications with the same UID.
+            for (int i = 0; i < sharedUidPackages.length; i++) {
+                final String sharedPackage = sharedUidPackages[i];
+                if (TextUtils.equals(packageName, sharedPackage)) {
+                    continue;
+                }
+                sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp,
+                        notExportedComponentNames, packageUid, reason, userIds, instantUserIds,
+                        broadcastAllowList, sharedPackage /* targetPackageName */,
+                        null /* requiredPermissions */);
+            }
+
         }
 
         if (!exportedComponentNames.isEmpty()) {
@@ -936,7 +954,8 @@
                 isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds);
         mHandler.post(() -> sendPackageChangedBroadcastInternal(
                 packageName, dontKillApp, componentNames, packageUid, reason, userIds,
-                instantUserIds, broadcastAllowList, setting.getPkg()));
+                instantUserIds, broadcastAllowList, setting.getPkg(),
+                snapshot.getSharedUserPackagesForPackage(packageName, userId)));
         mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
                 packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler);
     }
diff --git a/services/core/java/com/android/server/pm/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
index 745665b..527d680 100644
--- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java
+++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java
@@ -17,51 +17,240 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
+import static android.os.Process.SYSTEM_UID;
 
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.dependencyinstaller.DependencyInstallerCallback;
+import android.content.pm.dependencyinstaller.IDependencyInstallerCallback;
+import android.content.pm.dependencyinstaller.IDependencyInstallerService;
 import android.content.pm.parsing.PackageLite;
+import android.os.Handler;
 import android.os.OutcomeReceiver;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Helper class to interact with SDK Dependency Installer service.
  */
 public class InstallDependencyHelper {
-    private final SharedLibrariesImpl mSharedLibraries;
+    private static final String TAG = InstallDependencyHelper.class.getSimpleName();
+    private static final boolean DEBUG = true;
+    private static final String ACTION_INSTALL_DEPENDENCY =
+            "android.intent.action.INSTALL_DEPENDENCY";
+    // The maximum amount of time to wait before the system unbinds from the verifier.
+    private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6);
+    private static final long REQUEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1);
 
-    InstallDependencyHelper(SharedLibrariesImpl sharedLibraries) {
+    private final SharedLibrariesImpl mSharedLibraries;
+    private final Context mContext;
+    private final Object mRemoteServiceLock = new Object();
+
+    @GuardedBy("mRemoteServiceLock")
+    private ServiceConnector<IDependencyInstallerService> mRemoteService = null;
+
+    InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries) {
+        mContext = context;
         mSharedLibraries = sharedLibraries;
     }
 
-    void resolveLibraryDependenciesIfNeeded(PackageLite pkg,
-            OutcomeReceiver<Void, PackageManagerException> callback) {
-        final List<SharedLibraryInfo> missing;
+    void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId,
+            Handler handler, OutcomeReceiver<Void, PackageManagerException> origCallback) {
+        CallOnceProxy callback = new CallOnceProxy(handler, origCallback);
         try {
-            missing = mSharedLibraries.collectMissingSharedLibraryInfos(pkg);
+            resolveLibraryDependenciesIfNeededInternal(pkg, snapshot, userId, handler, callback);
         } catch (PackageManagerException e) {
             callback.onError(e);
-            return;
+        } catch (Exception e) {
+            onError(callback, e.getMessage());
         }
+    }
+
+
+    private void resolveLibraryDependenciesIfNeededInternal(PackageLite pkg, Computer snapshot,
+            int userId, Handler handler, CallOnceProxy callback) throws PackageManagerException {
+        final List<SharedLibraryInfo> missing =
+                mSharedLibraries.collectMissingSharedLibraryInfos(pkg);
 
         if (missing.isEmpty()) {
+            if (DEBUG) {
+                Slog.i(TAG, "No missing dependency for " + pkg);
+            }
             // No need for dependency resolution. Move to installation directly.
             callback.onResult(null);
             return;
         }
 
-        try {
-            bindToDependencyInstaller();
-        } catch (Exception e) {
-            PackageManagerException pe = new PackageManagerException(
-                    INSTALL_FAILED_MISSING_SHARED_LIBRARY, e.getMessage());
-            callback.onError(pe);
+        if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) {
+            onError(callback, "Dependency Installer Service not found");
+            return;
+        }
+
+        IDependencyInstallerCallback serviceCallback = new IDependencyInstallerCallback.Stub() {
+            @Override
+            public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException {
+                // TODO(b/372862145): Implement waiting for sessions to finish installation
+                callback.onResult(null);
+            }
+
+            @Override
+            public void onFailureToResolveAllDependencies() throws RemoteException {
+                onError(callback, "Failed to resolve all dependencies automatically");
+            }
+        };
+
+        boolean scheduleSuccess;
+        synchronized (mRemoteServiceLock) {
+            scheduleSuccess = mRemoteService.run(service -> {
+                service.onDependenciesRequired(missing,
+                        new DependencyInstallerCallback(serviceCallback.asBinder()));
+            });
+        }
+        if (!scheduleSuccess) {
+            onError(callback, "Failed to schedule job on Dependency Installer Service");
         }
     }
 
-    private void bindToDependencyInstaller() {
-        throw new IllegalStateException("Failed to bind to Dependency Installer");
+    private void onError(CallOnceProxy callback, String msg) {
+        PackageManagerException pe = new PackageManagerException(
+                INSTALL_FAILED_MISSING_SHARED_LIBRARY, msg);
+        callback.onError(pe);
     }
 
+    private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler,
+            Computer snapshot) {
+        synchronized (mRemoteServiceLock) {
+            if (mRemoteService != null) {
+                if (DEBUG) {
+                    Slog.i(TAG, "DependencyInstallerService already bound");
+                }
+                return true;
+            }
+        }
 
+        Intent serviceIntent = new Intent(ACTION_INSTALL_DEPENDENCY);
+        // TODO(b/372862145): Use RoleManager to find the package name
+        List<ResolveInfo> resolvedIntents = snapshot.queryIntentServicesInternal(
+                serviceIntent, /*resolvedType=*/ null, /*flags=*/0,
+                userId, SYSTEM_UID, Process.INVALID_PID,
+                /*includeInstantApps*/ false, /*resolveForStart*/ false);
+
+        if (resolvedIntents.isEmpty()) {
+            return false;
+        }
+
+
+        ResolveInfo resolveInfo = resolvedIntents.getFirst();
+        ComponentName componentName = resolveInfo.getComponentInfo().getComponentName();
+        serviceIntent.setComponent(componentName);
+
+        ServiceConnector<IDependencyInstallerService> serviceConnector =
+                new ServiceConnector.Impl<IDependencyInstallerService>(mContext, serviceIntent,
+                    Context.BIND_AUTO_CREATE, userId,
+                    IDependencyInstallerService.Stub::asInterface) {
+                    @Override
+                    protected Handler getJobHandler() {
+                        return handler;
+                    }
+
+                    @Override
+                    protected long getRequestTimeoutMs() {
+                        return REQUEST_TIMEOUT_MILLIS;
+                    }
+
+                    @Override
+                    protected long getAutoDisconnectTimeoutMs() {
+                        return UNBIND_TIMEOUT_MILLIS;
+                    }
+                };
+
+
+        synchronized (mRemoteServiceLock) {
+            // Some other thread managed to connect to the service first
+            if (mRemoteService != null) {
+                return true;
+            }
+            mRemoteService = serviceConnector;
+            mRemoteService.setServiceLifecycleCallbacks(
+                new ServiceConnector.ServiceLifecycleCallbacks<>() {
+                    @Override
+                    public void onDisconnected(@NonNull IDependencyInstallerService service) {
+                        Slog.w(TAG,
+                                "DependencyInstallerService " + componentName + " is disconnected");
+                        destroy();
+                    }
+
+                    @Override
+                    public void onBinderDied() {
+                        Slog.w(TAG, "DependencyInstallerService " + componentName + " has died");
+                        destroy();
+                    }
+
+                    private void destroy() {
+                        synchronized (mRemoteServiceLock) {
+                            if (mRemoteService != null) {
+                                mRemoteService.unbind();
+                                mRemoteService = null;
+                            }
+                        }
+                    }
+
+                });
+            AndroidFuture<IDependencyInstallerService> unusedFuture = mRemoteService.connect();
+        }
+        return true;
+    }
+
+    /**
+     * Ensure we call one of the outcomes only once, on the right handler.
+     *
+     * Repeated calls will be no-op.
+     */
+    private static class CallOnceProxy implements OutcomeReceiver<Void, PackageManagerException> {
+        private final Handler mHandler;
+        private final OutcomeReceiver<Void, PackageManagerException> mCallback;
+        @GuardedBy("this")
+        private boolean mCalled = false;
+
+        CallOnceProxy(Handler handler, OutcomeReceiver<Void, PackageManagerException> callback) {
+            mHandler = handler;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onResult(Void result) {
+            synchronized (this) {
+                if (!mCalled) {
+                    mHandler.post(() -> {
+                        mCallback.onResult(null);
+                    });
+                    mCalled = true;
+                }
+            }
+        }
+
+        @Override
+        public void onError(@NonNull PackageManagerException error) {
+            synchronized (this) {
+                if (!mCalled) {
+                    mHandler.post(() -> {
+                        mCallback.onError(error);
+                    });
+                    mCalled = true;
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 76ea0b9..4690e02 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -880,7 +880,8 @@
                 PackageInstaller.STATUS_PENDING_USER_ACTION);
         broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent);
         broadcastIntent.putExtra(Intent.EXTRA_USER, user);
-        sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent);
+        mPm.mHandler.post(
+            () -> sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent));
     }
 
     private void verifyUninstallPermissions() {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index eb70748..9b44f93 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -347,7 +347,7 @@
         synchronized (mVerificationPolicyPerUser) {
             mVerificationPolicyPerUser.put(USER_SYSTEM, DEFAULT_VERIFICATION_POLICY);
         }
-        mInstallDependencyHelper = new InstallDependencyHelper(
+        mInstallDependencyHelper = new InstallDependencyHelper(mContext,
                 mPm.mInjector.getSharedLibrariesImpl());
 
         LocalServices.getService(SystemServiceManager.class).startService(
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index e156b31..505b7e6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3428,8 +3428,8 @@
 
     private void resolveLibraryDependenciesIfNeeded() {
         synchronized (mLock) {
-            // TODO(b/372862145): Callback should be called on a handler passed as parameter
             mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(mPackageLite,
+                    mPm.snapshotComputer(), userId, mHandler,
                     new OutcomeReceiver<>() {
 
                         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7ef3582..961b4b3c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3606,6 +3606,13 @@
                 case "--force-verification":
                     sessionParams.setForceVerification();
                     break;
+                case "--disable-auto-install-dependencies":
+                    if (Flags.sdkDependencyInstaller()) {
+                        sessionParams.setEnableAutoInstallDependencies(false);
+                    } else {
+                        throw new IllegalArgumentException("Unknown option " + opt);
+                    }
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown option " + opt);
             }
@@ -4894,6 +4901,10 @@
                 + "#compiler_filters");
         pw.println("          or 'skip'");
         pw.println("      --force-verification: if set, enable the verification for this install");
+        if (Flags.sdkDependencyInstaller()) {
+            pw.println("      --disable-auto-install-dependencies: if set, any missing shared");
+            pw.println("          library dependencies will not be auto-installed");
+        }
         pw.println("");
         pw.println("  install-existing [--user USER_ID|all|current]");
         pw.println("       [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE");
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index fc54f68..17d7a14 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -1017,10 +1017,11 @@
                     boolean isSdkOrStatic = libraryType.equals(LIBRARY_TYPE_SDK)
                             || libraryType.equals(LIBRARY_TYPE_STATIC);
                     if (isSdkOrStatic && outMissingSharedLibraryInfos != null) {
-                        // TODO(b/372862145): Pass the CertDigest too
                         // If Dependency Installation is supported, try that instead of failing.
+                        final List<String> libCertDigests = Arrays.asList(requiredCertDigests[i]);
                         SharedLibraryInfo missingLibrary = new SharedLibraryInfo(
-                                libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE
+                                libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE,
+                                libCertDigests
                         );
                         outMissingSharedLibraryInfos.add(missingLibrary);
                     } else {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 5518bfa..1052c94 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1022,7 +1022,7 @@
                 // Close.
                 file.finishWrite(outs);
             } catch (IOException e) {
-                Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
+                Slog.w(TAG, "Failed to write to file " + file.getBaseFile(), e);
                 file.failWrite(outs);
             }
         }
@@ -1055,7 +1055,7 @@
                     final String tag = parser.getName();
                     if (depth == 1) {
                         if (!TAG_ROOT.equals(tag)) {
-                            Slog.e(TAG, "Invalid root tag: " + tag);
+                            Slog.v(TAG, "Invalid root tag: " + tag);
                             return;
                         }
                         continue;
@@ -1066,7 +1066,7 @@
                             mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE));
                             break;
                         default:
-                            Slog.e(TAG, "Invalid tag: " + tag);
+                            Slog.v(TAG, "Invalid tag: " + tag);
                             break;
                     }
                 }
@@ -1113,7 +1113,7 @@
                 // Remove all dangling bitmap files.
                 cleanupDanglingBitmapDirectoriesLocked(userId);
             } catch (XmlPullParserException | IOException e) {
-                Slog.e(TAG, "Failed to write to file " + file, e);
+                Slog.w(TAG, "Failed to write to file " + file, e);
                 file.failWrite(os);
             }
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 06e29c2..b2b8aaf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4984,7 +4984,10 @@
             res.getValue(com.android.internal.R.string.owner_name, mOwnerNameTypedValue, true);
             final CharSequence ownerName = mOwnerNameTypedValue.coerceToString();
             mOwnerName.set(ownerName != null ? ownerName.toString() : null);
+            // Invalidate when owners name changes due to config change.
+            UserManager.invalidateCacheOnUserDataChanged();
         }
+
     }
 
     private void scheduleWriteUserList() {
@@ -4997,6 +5000,8 @@
             Message msg = mHandler.obtainMessage(WRITE_USER_LIST_MSG);
             mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
         }
+        // Invalidate cache when {@link UserData} changed, but write was scheduled for later.
+        UserManager.invalidateCacheOnUserDataChanged();
     }
 
     private void scheduleWriteUser(@UserIdInt int userId) {
@@ -5009,6 +5014,8 @@
             Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userId);
             mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
         }
+        // Invalidate cache when {@link Data} changed, but write was scheduled for later.
+        UserManager.invalidateCacheOnUserDataChanged();
     }
 
     private ResilientAtomicFile getUserFile(int userId) {
@@ -5032,6 +5039,9 @@
         if (DBG) {
             debug("writeUserLP " + userData);
         }
+        // invalidate caches related to any {@link UserData} change.
+        UserManager.invalidateCacheOnUserDataChanged();
+
         try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) {
             FileOutputStream fos = null;
             try {
@@ -5196,6 +5206,8 @@
         if (DBG) {
             debug("writeUserList");
         }
+        // invalidate caches related to any {@link UserData} change.
+        UserManager.invalidateCacheOnUserDataChanged();
 
         try (ResilientAtomicFile file = getUserListFile()) {
             FileOutputStream fos = null;
@@ -7958,7 +7970,7 @@
                                     Settings.Secure.getIntForUser(mContext.getContentResolver(),
                                             HIDE_PRIVATESPACE_ENTRY_POINT, parentId) == 1);
                         } catch (Settings.SettingNotFoundException e) {
-                            throw new RuntimeException(e);
+                            config.putBoolean(PRIVATE_SPACE_ENTRYPOINT_HIDDEN, false);
                         }
                     }
                     return new LauncherUserInfo.Builder(userDetails.getName(),
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 4f67318..c9f66eb 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Icon;
 import android.hardware.input.AppLaunchData;
@@ -65,6 +66,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -84,6 +86,7 @@
     private static final String ATTRIBUTE_PACKAGE = "package";
     private static final String ATTRIBUTE_CLASS = "class";
     private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+    private static final String ATTRIBUTE_KEYCODE = "keycode";
     private static final String ATTRIBUTE_CATEGORY = "category";
     private static final String ATTRIBUTE_SHIFT = "shift";
     private static final String ATTRIBUTE_ROLE = "role";
@@ -167,6 +170,9 @@
                 }, UserHandle.ALL);
         mCurrentUser = currentUser;
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+    }
+
+    void onSystemReady() {
         loadShortcuts();
     }
 
@@ -335,6 +341,7 @@
         try {
             XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
             XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+            KeyCharacterMap virtualKcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
 
             while (true) {
                 XmlUtils.nextElement(parser);
@@ -353,15 +360,36 @@
                 String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
                 String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
                 String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);
+                final int keycode;
+                final int modifierState;
+                TypedArray a = mContext.getResources().obtainAttributes(parser,
+                        R.styleable.Bookmark);
+                try {
+                    keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN);
+                    modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0);
+                } finally {
+                    a.recycle();
+                }
 
+                if (TextUtils.isEmpty(shortcutName) && keycode != KeyEvent.KEYCODE_UNKNOWN) {
+                    // Try to find shortcutChar using keycode
+                    shortcutName = String.valueOf(virtualKcm.getDisplayLabel(keycode)).toLowerCase(
+                            Locale.ROOT);
+                }
                 if (TextUtils.isEmpty(shortcutName)) {
                     Log.w(TAG, "Shortcut required for bookmark with category=" + categoryName
                             + " packageName=" + packageName + " className=" + className
-                            + " role=" + roleName + "shiftName=" + shiftName);
+                            + " role=" + roleName + " shiftName=" + shiftName + " keycode= "
+                            + keycode + " modifierState= " + modifierState);
                     continue;
                 }
 
-                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
+                final boolean isShiftShortcut;
+                if (!TextUtils.isEmpty(shiftName)) {
+                    isShiftShortcut = shiftName.equals("true");
+                } else {
+                    isShiftShortcut = (modifierState & KeyEvent.META_SHIFT_ON) != 0;
+                }
 
                 if (modifierShortcutManagerRefactor()) {
                     final char shortcutChar = shortcutName.charAt(0);
@@ -376,7 +404,7 @@
                         bookmark = new RoleBookmark(shortcutChar, isShiftShortcut, roleName);
                     }
                     if (bookmark != null) {
-                        Log.d(TAG, "adding shortcut " + bookmark + "shift="
+                        Log.d(TAG, "adding shortcut " + bookmark + " shift="
                                 + isShiftShortcut + " char=" + shortcutChar);
                         mBookmarks.put(new Pair<>(shortcutChar, isShiftShortcut), bookmark);
                     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dda5bcf..85e7cfe 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6610,6 +6610,7 @@
         // In normal flow, systemReady is called before other system services are ready.
         // So it is better not to bind keyguard here.
         mKeyguardDelegate.onSystemReady();
+        mModifierShortcutManager.onSystemReady();
 
         mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
         if (mVrManagerInternal != null) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 0acfe92..37883f5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2332,6 +2332,8 @@
         Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
         try {
             // Phase 2: Handle wakefulness change and bookkeeping.
+            // Under lock, invalidate before set ensures caches won't return stale values.
+            mInjector.invalidateIsInteractiveCaches();
             mWakefulnessRaw = newWakefulness;
             mWakefulnessChanging = true;
             mDirty |= DIRTY_WAKEFULNESS;
@@ -2429,7 +2431,6 @@
     void onPowerGroupEventLocked(int event, PowerGroup powerGroup) {
         mWakefulnessChanging = true;
         mDirty |= DIRTY_WAKEFULNESS;
-        mInjector.invalidateIsInteractiveCaches();
         final int groupId = powerGroup.getGroupId();
         if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) {
             mPowerGroups.delete(groupId);
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 2c0ce25..17459df 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -33,11 +33,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.hardware.power.ChannelConfig;
+import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.GpuHeadroomParams;
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
 import android.hardware.power.WorkDuration;
 import android.os.Binder;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IHintManager;
@@ -90,6 +94,10 @@
 
     private static final int EVENT_CLEAN_UP_UID = 3;
     @VisibleForTesting  static final int CLEAN_UP_UID_DELAY_MILLIS = 1000;
+    private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000;
+    private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000;
+    private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1;
+    @VisibleForTesting static final int DEFAULT_HEADROOM_PID = -1;
 
 
     @VisibleForTesting final long mHintSessionPreferredRate;
@@ -160,10 +168,76 @@
 
     private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
     private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
+    private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms";
 
     private Boolean mFMQUsesIntegratedEventFlag = false;
 
-    @VisibleForTesting final IHintManager.Stub mService = new BinderService();
+    private final Object mCpuHeadroomLock = new Object();
+
+    private static class CpuHeadroomCacheItem {
+        long mExpiredTimeMillis;
+        CpuHeadroomParamsInternal mParams;
+        float[] mHeadroom;
+        long mPid;
+
+        CpuHeadroomCacheItem(long expiredTimeMillis, CpuHeadroomParamsInternal params,
+                float[] headroom, long pid) {
+            mExpiredTimeMillis = expiredTimeMillis;
+            mParams = params;
+            mPid = pid;
+            mHeadroom = headroom;
+        }
+
+        private boolean match(CpuHeadroomParamsInternal params, long pid) {
+            if (mParams == null && params == null) return true;
+            if (mParams != null) {
+                return mParams.equals(params) && pid == mPid;
+            }
+            return false;
+        }
+
+        private boolean isExpired() {
+            return System.currentTimeMillis() > mExpiredTimeMillis;
+        }
+    }
+
+    @GuardedBy("mCpuHeadroomLock")
+    private final List<CpuHeadroomCacheItem> mCpuHeadroomCache;
+    private final long mCpuHeadroomIntervalMillis;
+
+    private final Object mGpuHeadroomLock = new Object();
+
+    private static class GpuHeadroomCacheItem {
+        long mExpiredTimeMillis;
+        GpuHeadroomParamsInternal mParams;
+        float mHeadroom;
+
+        GpuHeadroomCacheItem(long expiredTimeMillis, GpuHeadroomParamsInternal params,
+                float headroom) {
+            mExpiredTimeMillis = expiredTimeMillis;
+            mParams = params;
+            mHeadroom = headroom;
+        }
+
+        private boolean match(GpuHeadroomParamsInternal params) {
+            if (mParams == null && params == null) return true;
+            if (mParams != null) {
+                return mParams.equals(params);
+            }
+            return false;
+        }
+
+        private boolean isExpired() {
+            return System.currentTimeMillis() > mExpiredTimeMillis;
+        }
+    }
+
+    @GuardedBy("mGpuHeadroomLock")
+    private final List<GpuHeadroomCacheItem> mGpuHeadroomCache;
+    private final long mGpuHeadroomIntervalMillis;
+
+    @VisibleForTesting
+    final IHintManager.Stub mService = new BinderService();
 
     public HintManagerService(Context context) {
         this(context, new Injector());
@@ -197,13 +271,72 @@
         mPowerHal = injector.createIPower();
         mPowerHalVersion = 0;
         mUsesFmq = false;
+        long cpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
+        long gpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
         if (mPowerHal != null) {
             try {
                 mPowerHalVersion = mPowerHal.getInterfaceVersion();
+                if (mPowerHal.getInterfaceVersion() >= 6) {
+                    if (SystemProperties.getBoolean(PROPERTY_USE_HAL_HEADROOMS, true)) {
+                        cpuHeadroomIntervalMillis = checkCpuHeadroomSupport();
+                        gpuHeadroomIntervalMillis = checkGpuHeadroomSupport();
+                    }
+                }
             } catch (RemoteException e) {
                 throw new IllegalStateException("Could not contact PowerHAL!", e);
             }
         }
+        mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis;
+        mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis;
+        if (mCpuHeadroomIntervalMillis > 0) {
+            mCpuHeadroomCache = new ArrayList<>(4);
+        } else {
+            mCpuHeadroomCache = null;
+        }
+        if (mGpuHeadroomIntervalMillis > 0) {
+            mGpuHeadroomCache = new ArrayList<>(2);
+        } else {
+            mGpuHeadroomCache = null;
+        }
+    }
+
+    private long checkCpuHeadroomSupport() {
+        try {
+            synchronized (mCpuHeadroomLock) {
+                final CpuHeadroomParams defaultParams = new CpuHeadroomParams();
+                defaultParams.pid = Process.myPid();
+                float[] ret = mPowerHal.getCpuHeadroom(defaultParams);
+                if (ret != null && ret.length > 0) {
+                    return Math.max(
+                            DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS,
+                            mPowerHal.getCpuHeadroomMinIntervalMillis());
+                }
+            }
+
+        } catch (UnsupportedOperationException e) {
+            Slog.w(TAG, "getCpuHeadroom HAL API is not supported", e);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API", e);
+        }
+        return HEADROOM_INTERVAL_UNSUPPORTED;
+    }
+
+    private long checkGpuHeadroomSupport() {
+        try {
+            synchronized (mGpuHeadroomLock) {
+                float ret = mPowerHal.getGpuHeadroom(new GpuHeadroomParams());
+                if (!Float.isNaN(ret)) {
+                    return Math.max(
+                            DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS,
+                            mPowerHal.getGpuHeadroomMinIntervalMillis());
+                }
+            }
+        } catch (UnsupportedOperationException e) {
+            Slog.w(TAG, "getGpuHeadroom HAL API is not supported", e);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API", e);
+        }
+        return HEADROOM_INTERVAL_UNSUPPORTED;
     }
 
     private ServiceThread createCleanUpThread() {
@@ -738,7 +871,7 @@
                 mLinked = false;
             }
             if (mConfig != null) {
-                try  {
+                try {
                     mPowerHal.closeSessionChannel(mTgid, mUid);
                 } catch (RemoteException e) {
                     throw new IllegalStateException("Failed to close session channel!", e);
@@ -982,13 +1115,13 @@
     }
 
     // returns the first invalid tid or null if not found
-    private Integer checkTidValid(int uid, int tgid, int [] tids, IntArray nonIsolated) {
+    private Integer checkTidValid(int uid, int tgid, int[] tids, IntArray nonIsolated) {
         // Make sure all tids belongs to the same UID (including isolated UID),
         // tids can belong to different application processes.
         List<Integer> isolatedPids = null;
         for (int i = 0; i < tids.length; i++) {
             int tid = tids[i];
-            final String[] procStatusKeys = new String[] {
+            final String[] procStatusKeys = new String[]{
                     "Uid:",
                     "Tgid:"
             };
@@ -1058,7 +1191,7 @@
                     Slogf.w(TAG, errMsg);
                     throw new SecurityException(errMsg);
                 }
-                if (resetOnForkEnabled()){
+                if (resetOnForkEnabled()) {
                     try {
                         for (int tid : tids) {
                             int policy = Process.getThreadScheduler(tid);
@@ -1214,6 +1347,124 @@
         }
 
         @Override
+        public float[] getCpuHeadroom(@Nullable CpuHeadroomParamsInternal params) {
+            if (mCpuHeadroomIntervalMillis <= 0) {
+                throw new UnsupportedOperationException();
+            }
+            CpuHeadroomParams halParams = new CpuHeadroomParams();
+            halParams.pid = Binder.getCallingPid();
+            if (params != null) {
+                halParams.calculationType = params.calculationType;
+                halParams.selectionType = params.selectionType;
+                if (params.usesDeviceHeadroom) {
+                    halParams.pid = DEFAULT_HEADROOM_PID;
+                }
+            }
+            synchronized (mCpuHeadroomLock) {
+                while (!mCpuHeadroomCache.isEmpty()) {
+                    if (mCpuHeadroomCache.getFirst().isExpired()) {
+                        mCpuHeadroomCache.removeFirst();
+                    } else {
+                        break;
+                    }
+                }
+                for (int i = 0; i < mCpuHeadroomCache.size(); ++i) {
+                    final CpuHeadroomCacheItem item = mCpuHeadroomCache.get(i);
+                    if (item.match(params, halParams.pid)) {
+                        item.mExpiredTimeMillis =
+                                System.currentTimeMillis() + mCpuHeadroomIntervalMillis;
+                        mCpuHeadroomCache.remove(i);
+                        mCpuHeadroomCache.add(item);
+                        return item.mHeadroom;
+                    }
+                }
+            }
+            // return from HAL directly
+            try {
+                float[] headroom = mPowerHal.getCpuHeadroom(halParams);
+                if (headroom == null || headroom.length == 0) {
+                    Slog.wtf(TAG,
+                            "CPU headroom from Power HAL is invalid: " + Arrays.toString(headroom));
+                    return new float[]{Float.NaN};
+                }
+                synchronized (mCpuHeadroomLock) {
+                    mCpuHeadroomCache.add(new CpuHeadroomCacheItem(
+                            System.currentTimeMillis() + mCpuHeadroomIntervalMillis,
+                            params, headroom, halParams.pid
+                    ));
+                }
+                return headroom;
+
+            } catch (RemoteException e) {
+                return new float[]{Float.NaN};
+            }
+        }
+
+        @Override
+        public float getGpuHeadroom(@Nullable GpuHeadroomParamsInternal params) {
+            if (mGpuHeadroomIntervalMillis <= 0) {
+                throw new UnsupportedOperationException();
+            }
+            GpuHeadroomParams halParams = new GpuHeadroomParams();
+            if (params != null) {
+                halParams.calculationType = params.calculationType;
+            }
+            synchronized (mGpuHeadroomLock) {
+                while (!mGpuHeadroomCache.isEmpty()) {
+                    if (mGpuHeadroomCache.getFirst().isExpired()) {
+                        mGpuHeadroomCache.removeFirst();
+                    } else {
+                        break;
+                    }
+                }
+                for (int i = 0; i < mGpuHeadroomCache.size(); ++i) {
+                    final GpuHeadroomCacheItem item = mGpuHeadroomCache.get(i);
+                    if (item.match(params)) {
+                        item.mExpiredTimeMillis =
+                                System.currentTimeMillis() + mGpuHeadroomIntervalMillis;
+                        mGpuHeadroomCache.remove(i);
+                        mGpuHeadroomCache.add(item);
+                        return item.mHeadroom;
+                    }
+                }
+            }
+            // return from HAL directly
+            try {
+                float headroom = mPowerHal.getGpuHeadroom(halParams);
+                if (Float.isNaN(headroom)) {
+                    Slog.wtf(TAG,
+                            "GPU headroom from Power HAL is NaN");
+                    return Float.NaN;
+                }
+                synchronized (mGpuHeadroomLock) {
+                    mGpuHeadroomCache.add(new GpuHeadroomCacheItem(
+                            System.currentTimeMillis() + mGpuHeadroomIntervalMillis,
+                            params, headroom
+                    ));
+                }
+                return headroom;
+            } catch (RemoteException e) {
+                return Float.NaN;
+            }
+        }
+
+        @Override
+        public long getCpuHeadroomMinIntervalMillis() throws RemoteException {
+            if (mCpuHeadroomIntervalMillis <= 0) {
+                throw new UnsupportedOperationException();
+            }
+            return mCpuHeadroomIntervalMillis;
+        }
+
+        @Override
+        public long getGpuHeadroomMinIntervalMillis() throws RemoteException {
+            if (mGpuHeadroomIntervalMillis <= 0) {
+                throw new UnsupportedOperationException();
+            }
+            return mGpuHeadroomIntervalMillis;
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
                 return;
@@ -1235,6 +1486,25 @@
                     }
                 }
             }
+            pw.println("CPU Headroom Interval: " + mCpuHeadroomIntervalMillis);
+            pw.println("GPU Headroom Interval: " + mGpuHeadroomIntervalMillis);
+            try {
+                CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal();
+                params.selectionType = CpuHeadroomParams.SelectionType.ALL;
+                params.usesDeviceHeadroom = true;
+                pw.println("CPU headroom: " + Arrays.toString(getCpuHeadroom(params)));
+                params = new CpuHeadroomParamsInternal();
+                params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+                params.usesDeviceHeadroom = true;
+                pw.println("CPU headroom per core: " + Arrays.toString(getCpuHeadroom(params)));
+            } catch (Exception e) {
+                pw.println("CPU headroom: N/A");
+            }
+            try {
+                pw.println("GPU headroom: " + getGpuHeadroom(null));
+            } catch (Exception e) {
+                pw.println("GPU headroom: N/A");
+            }
         }
 
         private void logPerformanceHintSessionAtom(int uid, long sessionId,
@@ -1467,7 +1737,7 @@
                             Slogf.w(TAG, errMsg);
                             throw new SecurityException(errMsg);
                         }
-                        if (resetOnForkEnabled()){
+                        if (resetOnForkEnabled()) {
                             try {
                                 for (int tid : tids) {
                                     int policy = Process.getThreadScheduler(tid);
diff --git a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
index 1260eee..e780be4 100644
--- a/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
+++ b/services/core/java/com/android/server/security/advancedprotection/AdvancedProtectionService.java
@@ -46,6 +46,7 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
 import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
+import com.android.server.security.advancedprotection.features.DisallowInstallUnknownSourcesAdvancedProtectionHook;
 
 import java.io.FileDescriptor;
 import java.util.ArrayList;
@@ -76,10 +77,9 @@
     }
 
     private void initFeatures(boolean enabled) {
-        // Empty until features are added.
-        // Examples:
-        // mHooks.add(new SideloadingAdvancedProtectionHook(mContext, enabled));
-        // mProviders.add(new WifiAdvancedProtectionProvider());
+        if (android.security.Flags.aapmFeatureDisableInstallUnknownSources()) {
+            mHooks.add(new DisallowInstallUnknownSourcesAdvancedProtectionHook(mContext, enabled));
+        }
     }
 
     // Only for tests
diff --git a/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
new file mode 100644
index 0000000..21752e5
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/features/DisallowInstallUnknownSourcesAdvancedProtectionHook.java
@@ -0,0 +1,73 @@
+/*
+ * 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.server.security.advancedprotection.features;
+
+import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
+import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserManager;
+import android.security.advancedprotection.AdvancedProtectionFeature;
+import android.util.Slog;
+
+/** @hide */
+public final class DisallowInstallUnknownSourcesAdvancedProtectionHook
+        extends AdvancedProtectionHook {
+    private static final String TAG = "AdvancedProtectionDisallowInstallUnknown";
+
+    private final AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(
+            FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
+    private final DevicePolicyManager mDevicePolicyManager;
+
+    public DisallowInstallUnknownSourcesAdvancedProtectionHook(@NonNull Context context,
+            boolean enabled) {
+        super(context, enabled);
+        mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+        onAdvancedProtectionChanged(enabled);
+    }
+
+    @NonNull
+    @Override
+    public AdvancedProtectionFeature getFeature() {
+        return mFeature;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void onAdvancedProtectionChanged(boolean enabled) {
+        if (enabled) {
+            Slog.d(TAG, "Setting DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
+            mDevicePolicyManager.addUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
+                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
+            return;
+        }
+        Slog.d(TAG, "Clearing DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
+        mDevicePolicyManager.clearUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
+                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
+
+        // TODO(b/369361373):
+        //  1. After clearing the restriction, set AppOpsManager.OP_REQUEST_INSTALL_PACKAGES to
+        //  disabled.
+        //  2. Update dialog strings.
+    }
+}
diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
similarity index 96%
rename from services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java
rename to services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
index b129fdc..b8a4a9c 100644
--- a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java
+++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.security.adaptiveauthentication;
+package com.android.server.security.authenticationpolicy;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 
@@ -55,8 +55,8 @@
 /**
  * @hide
  */
-public class AdaptiveAuthenticationService extends SystemService {
-    private static final String TAG = "AdaptiveAuthenticationService";
+public class AuthenticationPolicyService extends SystemService {
+    private static final String TAG = "AuthenticationPolicyService";
     private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
 
     @VisibleForTesting
@@ -78,12 +78,12 @@
     final SparseIntArray mFailedAttemptsForUser = new SparseIntArray();
     private final SparseLongArray mLastLockedTimestamp = new SparseLongArray();
 
-    public AdaptiveAuthenticationService(Context context) {
+    public AuthenticationPolicyService(Context context) {
         this(context, new LockPatternUtils(context));
     }
 
     @VisibleForTesting
-    public AdaptiveAuthenticationService(Context context, LockPatternUtils lockPatternUtils) {
+    public AuthenticationPolicyService(Context context, LockPatternUtils lockPatternUtils) {
         super(context);
         mLockPatternUtils = lockPatternUtils;
         mLockSettings = Objects.requireNonNull(
diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/OWNERS b/services/core/java/com/android/server/security/authenticationpolicy/OWNERS
similarity index 100%
rename from services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
rename to services/core/java/com/android/server/security/authenticationpolicy/OWNERS
diff --git a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java b/services/core/java/com/android/server/security/forensic/ForensicEventTransportConnection.java
similarity index 69%
rename from services/core/java/com/android/server/security/forensic/BackupTransportConnection.java
rename to services/core/java/com/android/server/security/forensic/ForensicEventTransportConnection.java
index caca011..b85199e 100644
--- a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java
+++ b/services/core/java/com/android/server/security/forensic/ForensicEventTransportConnection.java
@@ -16,15 +16,19 @@
 
 package com.android.server.security.forensic;
 
+import static android.Manifest.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.security.forensic.ForensicEvent;
-import android.security.forensic.IBackupTransport;
+import android.security.forensic.IForensicEventTransport;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -36,20 +40,20 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-public class BackupTransportConnection implements ServiceConnection {
-    private static final String TAG = "BackupTransportConnection";
+public class ForensicEventTransportConnection implements ServiceConnection {
+    private static final String TAG = "ForensicEventTransportConnection";
     private static final long FUTURE_TIMEOUT_MILLIS = 60 * 1000; // 1 mins
     private final Context mContext;
-    private String mForensicBackupTransportConfig;
-    volatile IBackupTransport mService;
+    private String mForensicEventTransportConfig;
+    volatile IForensicEventTransport mService;
 
-    public BackupTransportConnection(Context context) {
+    public ForensicEventTransportConnection(Context context) {
         mContext = context;
         mService = null;
     }
 
     /**
-     * Initialize the BackupTransport binder service.
+     * Initialize the ForensicEventTransport binder service.
      * @return Whether the initialization succeed.
      */
     public boolean initialize() {
@@ -74,7 +78,7 @@
     }
 
     /**
-     * Add data to the BackupTransport binder service.
+     * Add data to the ForensicEventTransport binder service.
      * @param data List of ForensicEvent.
      * @return Whether the data is added to the binder service.
      */
@@ -109,21 +113,37 @@
             return future.get(FUTURE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException
                  | CancellationException e) {
-            Slog.w(TAG, "Failed to get result from transport:", e);
+            Slog.e(TAG, "Failed to get result from transport:", e);
             return null;
         }
     }
 
     private boolean bindService() {
-        mForensicBackupTransportConfig = mContext.getString(
-                com.android.internal.R.string.config_forensicBackupTransport);
-        if (TextUtils.isEmpty(mForensicBackupTransportConfig)) {
+        mForensicEventTransportConfig = mContext.getString(
+                com.android.internal.R.string.config_forensicEventTransport);
+        if (TextUtils.isEmpty(mForensicEventTransportConfig)) {
+            Slog.e(TAG, "config_forensicEventTransport is empty");
             return false;
         }
 
         ComponentName serviceComponent =
-                ComponentName.unflattenFromString(mForensicBackupTransportConfig);
+                ComponentName.unflattenFromString(mForensicEventTransportConfig);
         if (serviceComponent == null) {
+            Slog.e(TAG, "Can't get serviceComponent name");
+            return false;
+        }
+
+        try {
+            ServiceInfo serviceInfo = mContext.getPackageManager().getServiceInfo(serviceComponent,
+                    0 /* flags */);
+            if (!BIND_FORENSIC_EVENT_TRANSPORT_SERVICE.equals(serviceInfo.permission)) {
+                Slog.e(TAG, serviceComponent.flattenToShortString()
+                        + " is not declared with the permission "
+                        + "\"" + BIND_FORENSIC_EVENT_TRANSPORT_SERVICE + "\"");
+                return false;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.e(TAG, "Unable to find serviceComponent");
             return false;
         }
 
@@ -143,7 +163,7 @@
 
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
-        mService = IBackupTransport.Stub.asInterface(service);
+        mService = IForensicEventTransport.Stub.asInterface(service);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/security/forensic/ForensicService.java b/services/core/java/com/android/server/security/forensic/ForensicService.java
index 01f630b..2be068f 100644
--- a/services/core/java/com/android/server/security/forensic/ForensicService.java
+++ b/services/core/java/com/android/server/security/forensic/ForensicService.java
@@ -16,11 +16,16 @@
 
 package com.android.server.security.forensic;
 
+import static android.Manifest.permission.MANAGE_FORENSIC_STATE;
+import static android.Manifest.permission.READ_FORENSIC_STATE;
+
+import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PermissionEnforcer;
 import android.os.RemoteException;
 import android.security.forensic.ForensicEvent;
 import android.security.forensic.IForensicService;
@@ -41,16 +46,15 @@
 public class ForensicService extends SystemService {
     private static final String TAG = "ForensicService";
 
-    private static final int MSG_MONITOR_STATE = 0;
-    private static final int MSG_MAKE_VISIBLE = 1;
-    private static final int MSG_MAKE_INVISIBLE = 2;
-    private static final int MSG_ENABLE = 3;
-    private static final int MSG_DISABLE = 4;
-    private static final int MSG_BACKUP = 5;
+    private static final int MAX_STATE_CALLBACK_NUM = 16;
+    private static final int MSG_ADD_STATE_CALLBACK = 0;
+    private static final int MSG_REMOVE_STATE_CALLBACK = 1;
+    private static final int MSG_ENABLE = 2;
+    private static final int MSG_DISABLE = 3;
+    private static final int MSG_TRANSPORT = 4;
 
     private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN;
-    private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE;
-    private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE;
+    private static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED;
     private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED;
 
     private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN;
@@ -58,19 +62,19 @@
             IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
     private static final int ERROR_INVALID_STATE_TRANSITION =
             IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION;
-    private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE =
-            IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE;
+    private static final int ERROR_TRANSPORT_UNAVAILABLE =
+            IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
     private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
             IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
 
     private final Context mContext;
     private final Handler mHandler;
-    private final BackupTransportConnection mBackupTransportConnection;
+    private final ForensicEventTransportConnection mForensicEventTransportConnection;
     private final DataAggregator mDataAggregator;
     private final BinderService mBinderService;
 
-    private final ArrayList<IForensicServiceStateCallback> mStateMonitors = new ArrayList<>();
-    private volatile int mState = STATE_INVISIBLE;
+    private final ArrayList<IForensicServiceStateCallback> mStateCallbacks = new ArrayList<>();
+    private volatile int mState = STATE_DISABLED;
 
     public ForensicService(@NonNull Context context) {
         this(new InjectorImpl(context));
@@ -81,9 +85,9 @@
         super(injector.getContext());
         mContext = injector.getContext();
         mHandler = new EventHandler(injector.getLooper(), this);
-        mBackupTransportConnection = injector.getBackupTransportConnection();
+        mForensicEventTransportConnection = injector.getForensicEventransportConnection();
         mDataAggregator = injector.getDataAggregator(this);
-        mBinderService = new BinderService(this);
+        mBinderService = new BinderService(this, injector.getPermissionEnforcer());
     }
 
     @VisibleForTesting
@@ -94,32 +98,36 @@
     private static final class BinderService extends IForensicService.Stub {
         final ForensicService mService;
 
-        BinderService(ForensicService service)  {
+        BinderService(ForensicService service, @NonNull PermissionEnforcer permissionEnforcer)  {
+            super(permissionEnforcer);
             mService = service;
         }
 
         @Override
-        public void monitorState(IForensicServiceStateCallback callback) {
-            mService.mHandler.obtainMessage(MSG_MONITOR_STATE, callback).sendToTarget();
+        @EnforcePermission(READ_FORENSIC_STATE)
+        public void addStateCallback(IForensicServiceStateCallback callback) {
+            addStateCallback_enforcePermission();
+            mService.mHandler.obtainMessage(MSG_ADD_STATE_CALLBACK, callback).sendToTarget();
         }
 
         @Override
-        public void makeVisible(IForensicServiceCommandCallback callback) {
-            mService.mHandler.obtainMessage(MSG_MAKE_VISIBLE, callback).sendToTarget();
+        @EnforcePermission(READ_FORENSIC_STATE)
+        public void removeStateCallback(IForensicServiceStateCallback callback) {
+            removeStateCallback_enforcePermission();
+            mService.mHandler.obtainMessage(MSG_REMOVE_STATE_CALLBACK, callback).sendToTarget();
         }
 
         @Override
-        public void makeInvisible(IForensicServiceCommandCallback callback) {
-            mService.mHandler.obtainMessage(MSG_MAKE_INVISIBLE, callback).sendToTarget();
-        }
-
-        @Override
+        @EnforcePermission(MANAGE_FORENSIC_STATE)
         public void enable(IForensicServiceCommandCallback callback) {
+            enable_enforcePermission();
             mService.mHandler.obtainMessage(MSG_ENABLE, callback).sendToTarget();
         }
 
         @Override
+        @EnforcePermission(MANAGE_FORENSIC_STATE)
         public void disable(IForensicServiceCommandCallback callback) {
+            disable_enforcePermission();
             mService.mHandler.obtainMessage(MSG_DISABLE, callback).sendToTarget();
         }
     }
@@ -135,24 +143,18 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_MONITOR_STATE:
+                case MSG_ADD_STATE_CALLBACK:
                     try {
-                        mService.monitorState(
+                        mService.addStateCallback(
                                 (IForensicServiceStateCallback) msg.obj);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "RemoteException", e);
                     }
                     break;
-                case MSG_MAKE_VISIBLE:
+                case MSG_REMOVE_STATE_CALLBACK:
                     try {
-                        mService.makeVisible((IForensicServiceCommandCallback) msg.obj);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "RemoteException", e);
-                    }
-                    break;
-                case MSG_MAKE_INVISIBLE:
-                    try {
-                        mService.makeInvisible((IForensicServiceCommandCallback) msg.obj);
+                        mService.removeStateCallback(
+                                (IForensicServiceStateCallback) msg.obj);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "RemoteException", e);
                     }
@@ -171,8 +173,8 @@
                         Slog.e(TAG, "RemoteException", e);
                     }
                     break;
-                case MSG_BACKUP:
-                    mService.backup((List<ForensicEvent>) msg.obj);
+                case MSG_TRANSPORT:
+                    mService.transport((List<ForensicEvent>) msg.obj);
                     break;
                 default:
                     Slog.w(TAG, "Unknown message: " + msg.what);
@@ -180,103 +182,83 @@
         }
     }
 
-    private void monitorState(IForensicServiceStateCallback callback) throws RemoteException {
-        for (int i = 0; i < mStateMonitors.size(); i++) {
-            if (mStateMonitors.get(i).asBinder() == callback.asBinder()) {
+    private void addStateCallback(IForensicServiceStateCallback callback) throws RemoteException {
+        for (int i = 0; i < mStateCallbacks.size(); i++) {
+            if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) {
                 return;
             }
         }
-        mStateMonitors.add(callback);
+        mStateCallbacks.add(callback);
         callback.onStateChange(mState);
     }
 
-    private void notifyStateMonitors() throws RemoteException {
-        for (int i = 0; i < mStateMonitors.size(); i++) {
-            mStateMonitors.get(i).onStateChange(mState);
+    private void removeStateCallback(IForensicServiceStateCallback callback)
+            throws RemoteException {
+        for (int i = 0; i < mStateCallbacks.size(); i++) {
+            if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) {
+                mStateCallbacks.remove(i);
+                return;
+            }
         }
     }
 
-    private void makeVisible(IForensicServiceCommandCallback callback) throws RemoteException {
-        switch (mState) {
-            case STATE_INVISIBLE:
-                if (!mDataAggregator.initialize()) {
-                    callback.onFailure(ERROR_DATA_SOURCE_UNAVAILABLE);
-                    break;
-                }
-                mState = STATE_VISIBLE;
-                notifyStateMonitors();
-                callback.onSuccess();
-                break;
-            case STATE_VISIBLE:
-                callback.onSuccess();
-                break;
-            default:
-                callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
+    private void notifyStateMonitors() {
+        if (mStateCallbacks.size() >= MAX_STATE_CALLBACK_NUM) {
+            mStateCallbacks.removeFirst();
         }
-    }
 
-    private void makeInvisible(IForensicServiceCommandCallback callback) throws RemoteException {
-        switch (mState) {
-            case STATE_VISIBLE:
-            case STATE_ENABLED:
-                mState = STATE_INVISIBLE;
-                notifyStateMonitors();
-                callback.onSuccess();
-                break;
-            case STATE_INVISIBLE:
-                callback.onSuccess();
-                break;
-            default:
-                callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
+        for (int i = 0; i < mStateCallbacks.size(); i++) {
+            try {
+                mStateCallbacks.get(i).onStateChange(mState);
+            } catch (RemoteException e) {
+                mStateCallbacks.remove(i);
+            }
         }
     }
 
     private void enable(IForensicServiceCommandCallback callback) throws RemoteException {
-        switch (mState) {
-            case STATE_VISIBLE:
-                if (!mBackupTransportConnection.initialize()) {
-                    callback.onFailure(ERROR_BACKUP_TRANSPORT_UNAVAILABLE);
-                    break;
-                }
-                mDataAggregator.enable();
-                mState = STATE_ENABLED;
-                notifyStateMonitors();
-                callback.onSuccess();
-                break;
-            case STATE_ENABLED:
-                callback.onSuccess();
-                break;
-            default:
-                callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
+        if (mState == STATE_ENABLED) {
+            callback.onSuccess();
+            return;
         }
+
+        // TODO: temporarily disable the following for the CTS ForensicManagerTest.
+        //  Enable it when the transport component is ready.
+        // if (!mForensicEventTransportConnection.initialize()) {
+        //     callback.onFailure(ERROR_TRANSPORT_UNAVAILABLE);
+        //   return;
+        // }
+
+        mDataAggregator.enable();
+        mState = STATE_ENABLED;
+        notifyStateMonitors();
+        callback.onSuccess();
     }
 
     private void disable(IForensicServiceCommandCallback callback) throws RemoteException {
-        switch (mState) {
-            case STATE_ENABLED:
-                mBackupTransportConnection.release();
-                mDataAggregator.disable();
-                mState = STATE_VISIBLE;
-                notifyStateMonitors();
-                callback.onSuccess();
-                break;
-            case STATE_VISIBLE:
-                callback.onSuccess();
-                break;
-            default:
-                callback.onFailure(ERROR_INVALID_STATE_TRANSITION);
+        if (mState == STATE_DISABLED) {
+            callback.onSuccess();
+            return;
         }
+
+        // TODO: temporarily disable the following for the CTS ForensicManagerTest.
+        //  Enable it when the transport component is ready.
+        // mForensicEventTransportConnection.release();
+        mDataAggregator.disable();
+        mState = STATE_DISABLED;
+        notifyStateMonitors();
+        callback.onSuccess();
     }
 
     /**
      * Add a list of ForensicEvent.
      */
     public void addNewData(List<ForensicEvent> events) {
-        mHandler.obtainMessage(MSG_BACKUP, events).sendToTarget();
+        mHandler.obtainMessage(MSG_TRANSPORT, events).sendToTarget();
     }
 
-    private void backup(List<ForensicEvent> events) {
-        mBackupTransportConnection.addData(events);
+    private void transport(List<ForensicEvent> events) {
+        mForensicEventTransportConnection.addData(events);
     }
 
     @Override
@@ -296,9 +278,11 @@
     interface Injector {
         Context getContext();
 
+        PermissionEnforcer getPermissionEnforcer();
+
         Looper getLooper();
 
-        BackupTransportConnection getBackupTransportConnection();
+        ForensicEventTransportConnection getForensicEventransportConnection();
 
         DataAggregator getDataAggregator(ForensicService forensicService);
     }
@@ -315,6 +299,10 @@
             return mContext;
         }
 
+        @Override
+        public PermissionEnforcer getPermissionEnforcer() {
+            return PermissionEnforcer.fromContext(mContext);
+        }
 
         @Override
         public Looper getLooper() {
@@ -326,8 +314,8 @@
         }
 
         @Override
-        public BackupTransportConnection getBackupTransportConnection() {
-            return new BackupTransportConnection(mContext);
+        public ForensicEventTransportConnection getForensicEventransportConnection() {
+            return new ForensicEventTransportConnection(mContext);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
index 0f1aa42..e1b49c4 100644
--- a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
+++ b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java
@@ -22,9 +22,7 @@
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.Context;
 import android.security.forensic.ForensicEvent;
-import android.util.ArrayMap;
 
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -34,10 +32,6 @@
 public class SecurityLogSource implements DataSource {
 
     private static final String TAG = "Forensic SecurityLogSource";
-    private static final String EVENT_TYPE = "SecurityEvent";
-    private static final String EVENT_TAG = "TAG";
-    private static final String EVENT_TIME = "TIME";
-    private static final String EVENT_DATA = "DATA";
 
     private SecurityEventCallback mEventCallback = new SecurityEventCallback();
     private DevicePolicyManager mDpm;
@@ -94,46 +88,9 @@
             List<ForensicEvent> forensicEvents =
                     events.stream()
                             .filter(event -> event != null)
-                            .map(event -> toForensicEvent(event))
+                            .map(event -> new ForensicEvent(event))
                             .collect(Collectors.toList());
             mDataAggregator.addBatchData(forensicEvents);
         }
-
-        private ForensicEvent toForensicEvent(SecurityEvent event) {
-            ArrayMap<String, String> keyValuePairs = new ArrayMap<>();
-            keyValuePairs.put(EVENT_TIME, String.valueOf(event.getTimeNanos()));
-            // TODO: Map tag to corresponding string
-            keyValuePairs.put(EVENT_TAG, String.valueOf(event.getTag()));
-            keyValuePairs.put(EVENT_DATA, eventDataToString(event.getData()));
-            return new ForensicEvent(EVENT_TYPE, keyValuePairs);
-        }
-
-        /**
-         * Convert event data to a String.
-         *
-         * @param obj Object containing an Integer, Long, Float, String, null, or Object[] of the
-         *     same.
-         * @return String representation of event data.
-         */
-        private String eventDataToString(Object obj) {
-            if (obj == null) {
-                return "";
-            } else if (obj instanceof Integer
-                    || obj instanceof Long
-                    || obj instanceof Float
-                    || obj instanceof String) {
-                return String.valueOf(obj);
-            } else if (obj instanceof Object[]) {
-                Object[] objArray = (Object[]) obj;
-                String[] strArray = new String[objArray.length];
-                for (int i = 0; i < objArray.length; ++i) {
-                    strArray[i] = eventDataToString(objArray[i]);
-                }
-                return Arrays.toString((String[]) strArray);
-            } else {
-                throw new IllegalArgumentException(
-                        "Unsupported data type: " + obj.getClass().getSimpleName());
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/stats/Android.bp b/services/core/java/com/android/server/stats/Android.bp
index f7955e8..40923b6 100644
--- a/services/core/java/com/android/server/stats/Android.bp
+++ b/services/core/java/com/android/server/stats/Android.bp
@@ -11,3 +11,10 @@
     name: "stats_flags_lib",
     aconfig_declarations: "stats_flags",
 }
+
+java_aconfig_library {
+    name: "stats_flags_lib_host",
+    aconfig_declarations: "stats_flags",
+    host_supported: true,
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 54e4f8e..40ea931 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -61,6 +61,10 @@
 import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS__SOFTWARE_SHORTCUT_TYPE__UNKNOWN_TYPE;
 import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC;
 import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_IO;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_MEMORY;
+import static com.android.internal.util.FrameworkStatsLog.PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__GEO;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__MANUAL;
 import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__TELEPHONY;
@@ -68,6 +72,7 @@
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.stats.Flags.accumulateNetworkStatsSinceBoot;
 import static com.android.server.stats.Flags.addMobileBytesTransferByProcStatePuller;
+import static com.android.server.stats.Flags.addPressureStallInformationPuller;
 import static com.android.server.stats.Flags.applyNetworkStatsPollRateLimit;
 import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -234,6 +239,8 @@
 import com.android.server.stats.pull.netstats.NetworkStatsAccumulator;
 import com.android.server.stats.pull.netstats.NetworkStatsExt;
 import com.android.server.stats.pull.netstats.SubInfo;
+import com.android.server.stats.pull.psi.PsiData;
+import com.android.server.stats.pull.psi.PsiExtractor;
 import com.android.server.storage.DiskStatsFileLogger;
 import com.android.server.storage.DiskStatsLoggingService;
 import com.android.server.timezonedetector.MetricsTimeZoneDetectorState;
@@ -459,6 +466,10 @@
     public static final boolean ENABLE_MOBILE_DATA_STATS_AGGREGATED_PULLER =
                 addMobileBytesTransferByProcStatePuller();
 
+    // Whether or not to enable the new puller with pressure stall information.
+    public static final boolean ENABLE_PRESSURE_STALL_INFORMATION_PULLER =
+                addPressureStallInformationPuller();
+
     // Puller locks
     private final Object mDataBytesTransferLock = new Object();
     private final Object mBluetoothBytesTransferLock = new Object();
@@ -835,6 +846,8 @@
                         return pullHdrCapabilities(atomTag, data);
                     case FrameworkStatsLog.CACHED_APPS_HIGH_WATERMARK:
                         return pullCachedAppsHighWatermark(atomTag, data);
+                    case FrameworkStatsLog.PRESSURE_STALL_INFORMATION:
+                        return pullPressureStallInformation(atomTag, data);
                     default:
                         throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                 }
@@ -1045,6 +1058,9 @@
         registerPinnerServiceStats();
         registerHdrCapabilitiesPuller();
         registerCachedAppsHighWatermarkPuller();
+        if (ENABLE_PRESSURE_STALL_INFORMATION_PULLER) {
+            registerPressureStallInformation();
+        }
     }
 
     private void initMobileDataStatsPuller() {
@@ -5156,6 +5172,55 @@
         );
     }
 
+    private void registerPressureStallInformation() {
+        int tagId = FrameworkStatsLog.PRESSURE_STALL_INFORMATION;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null,
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl
+        );
+    }
+
+    int pullPressureStallInformation(int atomTag, List<StatsEvent> pulledData) {
+        PsiExtractor psiExtractor = new PsiExtractor();
+        for (PsiData.ResourceType resourceType: PsiData.ResourceType.values()) {
+            PsiData psiData = psiExtractor.getPsiData(resourceType);
+            if (psiData == null) {
+                Slog.e(
+                        TAG,
+                        "Failed to pull PressureStallInformation atom for resource: "
+                                + resourceType.toString());
+                continue;
+            }
+            pulledData.add(FrameworkStatsLog.buildStatsEvent(
+                    atomTag,
+                    toProtoPsiResourceType(psiData.getResourceType()),
+                    psiData.getSomeAvg10SecPercentage(),
+                    psiData.getSomeAvg60SecPercentage(),
+                    psiData.getSomeAvg300SecPercentage(),
+                    psiData.getSomeTotalUsec(),
+                    psiData.getFullAvg10SecPercentage(),
+                    psiData.getFullAvg60SecPercentage(),
+                    psiData.getFullAvg300SecPercentage(),
+                    psiData.getFullTotalUsec()));
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
+    private int toProtoPsiResourceType(PsiData.ResourceType resourceType) {
+        if (resourceType == PsiData.ResourceType.CPU) {
+            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_CPU;
+        } else if (resourceType == PsiData.ResourceType.MEMORY) {
+            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_MEMORY;
+        } else if (resourceType == PsiData.ResourceType.IO) {
+            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_IO;
+        } else {
+            return PRESSURE_STALL_INFORMATION__PSI_RESOURCE__PSI_RESOURCE_UNKNOWN;
+        }
+    }
+
+
     int pullSystemServerPinnerStats(int atomTag, List<StatsEvent> pulledData) {
         PinnerService pinnerService = LocalServices.getService(PinnerService.class);
         List<PinnedFileStats> pinnedFileStats = pinnerService.dumpDataForStatsd();
diff --git a/services/core/java/com/android/server/stats/stats_flags.aconfig b/services/core/java/com/android/server/stats/stats_flags.aconfig
index 8686458f..f5f3174 100644
--- a/services/core/java/com/android/server/stats/stats_flags.aconfig
+++ b/services/core/java/com/android/server/stats/stats_flags.aconfig
@@ -38,3 +38,11 @@
     bug: "352537247"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "add_pressure_stall_information_puller"
+    namespace: "statsd"
+    description: "Adds PressureStallInformation atom logging"
+    bug: "365731097"
+    is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
index 42203b1..07d9ad1 100644
--- a/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
+++ b/services/core/java/com/android/server/vibrator/AbstractVibratorStep.java
@@ -112,6 +112,14 @@
     }
 
     protected void stopVibrating() {
+        if (conductor.isInSession) {
+            if (VibrationThread.DEBUG) {
+                Slog.d(VibrationThread.TAG,
+                        "Vibration in session, skipping request to turn off vibrator "
+                                + getVibratorId());
+            }
+            return;
+        }
         if (VibrationThread.DEBUG) {
             Slog.d(VibrationThread.TAG,
                     "Turning off vibrator " + getVibratorId());
diff --git a/services/core/java/com/android/server/vibrator/DeviceAdapter.java b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
index 751e83c..370f212 100644
--- a/services/core/java/com/android/server/vibrator/DeviceAdapter.java
+++ b/services/core/java/com/android/server/vibrator/DeviceAdapter.java
@@ -55,8 +55,9 @@
 
     DeviceAdapter(VibrationSettings settings, SparseArray<VibratorController> vibrators) {
         mSegmentAdapters = Arrays.asList(
-                // TODO(b/167947076): add filter that removes unsupported primitives
                 // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback
+                // Updates primitive delays to hardware supported pauses
+                new PrimitiveDelayAdapter(),
                 // Convert segments based on device capabilities
                 new RampToStepAdapter(settings.getRampStepDuration()),
                 new StepToRampAdapter(),
@@ -71,7 +72,9 @@
         );
         mSegmentsValidators = List.of(
                 // Validate Pwle segments base on the vibrators frequency range
-                new PwleSegmentsValidator()
+                new PwleSegmentsValidator(),
+                // Validate primitive segments based on device support
+                new PrimitiveSegmentsValidator()
         );
         mAvailableVibrators = vibrators;
         mAvailableVibratorIds = new int[vibrators.size()];
diff --git a/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java b/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java
new file mode 100644
index 0000000..d63fffd
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/PrimitiveDelayAdapter.java
@@ -0,0 +1,116 @@
+/*
+ * 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.server.vibrator;
+
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+
+import android.os.VibrationEffect.Composition.DelayType;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationEffectSegment;
+
+import java.util.List;
+
+/**
+ * Adapter that converts between {@link DelayType} and the HAL supported pause delays.
+ *
+ * <p>Primitives that overlap due to the delays being shorter than the previous segments will be
+ * dropped from the effect here. Relative timings will still use the dropped primitives to preserve
+ * the design intention.
+ */
+final class PrimitiveDelayAdapter implements VibrationSegmentsAdapter {
+
+    PrimitiveDelayAdapter() {
+    }
+
+    @Override
+    public int adaptToVibrator(VibratorInfo info, List<VibrationEffectSegment> segments,
+            int repeatIndex) {
+        if (!Flags.primitiveCompositionAbsoluteDelay()) {
+            return repeatIndex;
+        }
+        int previousStartOffset = 0;
+        int segmentCount = segments.size();
+        for (int i = 0; i < segmentCount; i++) {
+            VibrationEffectSegment segment = segments.get(i);
+            if (i == repeatIndex) {
+                // Crossed the repeat line, reset start offset so repeating block is independent.
+                previousStartOffset = 0;
+            }
+
+            if (!(segment instanceof PrimitiveSegment primitive)
+                    || (primitive.getDelayType() == DELAY_TYPE_PAUSE)) {
+                // Effect will play normally, keep track of its start offset.
+                previousStartOffset = -calculateEffectDuration(info, segment);
+                continue;
+            }
+
+            int pause = calculatePause(primitive, previousStartOffset);
+            if (pause >= 0) {
+                segments.set(i, toPrimitiveWithPause(primitive, pause));
+                // Delay will be ignored from this calculation.
+                previousStartOffset = -calculateEffectDuration(info, primitive);
+            } else {
+                // Primitive overlapping with previous segment, ignore it.
+                segments.remove(i);
+                if (repeatIndex > i) {
+                    repeatIndex--;
+                }
+                segmentCount--;
+                i--;
+
+                // Keep the intended start time for future calculations. Here is an example:
+                // 10 20 30 40 50 60 70 | Timeline (D = relative delay, E = effect duration)
+                //  D  E  E  E  E       | D=10, E=40 | offset = 0   | pause = 10  | OK
+                //     D  E  E          | D=10, E=20 | offset = -40 | pause = -30 | IGNORED
+                //        D  E  E       | D=10, E=20 | offset = -30 | pause = -20 | IGNORED
+                //           D  E  E    | D=10, E=20 | offset = -20 | pause = -10 | IGNORED
+                //              D  E  E | D=10, E=20 | offset = -10 | pause = 0   | OK
+                previousStartOffset = pause;
+            }
+        }
+        return repeatIndex;
+    }
+
+    private static int calculatePause(PrimitiveSegment primitive, int previousStartOffset) {
+        if (primitive.getDelayType() == DELAY_TYPE_RELATIVE_START_OFFSET) {
+            return previousStartOffset + primitive.getDelay();
+        }
+        return primitive.getDelay();
+    }
+
+    private static int calculateEffectDuration(VibratorInfo info, VibrationEffectSegment segment) {
+        long segmentDuration = segment.getDuration(info);
+        if (segmentDuration < 0) {
+            // Duration unknown, default to zero.
+            return 0;
+        }
+        int effectDuration = (int) segmentDuration;
+        if (segment instanceof PrimitiveSegment primitive) {
+            // Ignore primitive delays from effect duration.
+            effectDuration -= primitive.getDelay();
+        }
+        return effectDuration;
+    }
+
+    private static PrimitiveSegment toPrimitiveWithPause(PrimitiveSegment primitive, int pause) {
+        return new PrimitiveSegment(primitive.getPrimitiveId(), primitive.getScale(),
+                pause, DELAY_TYPE_PAUSE);
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java b/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java
new file mode 100644
index 0000000..a1567fc
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/PrimitiveSegmentsValidator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.vibrator;
+
+import android.annotation.SuppressLint;
+import android.hardware.vibrator.IVibrator;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.VibrationEffectSegment;
+
+import java.util.List;
+
+/**
+ * Validates primitive segments to ensure they are compatible with the device's capabilities.
+ *
+ * <p>The segments will be considered invalid if the device does not have
+ * {@link IVibrator#CAP_COMPOSE_EFFECTS} or if one of the primitives is not supported.
+ */
+final class PrimitiveSegmentsValidator implements VibrationSegmentsValidator {
+
+    @SuppressLint("WrongConstant") // using primitive id from validated segment
+    @Override
+    public boolean hasValidSegments(VibratorInfo info, List<VibrationEffectSegment> segments) {
+        int segmentCount = segments.size();
+        for (int i = 0; i < segmentCount; i++) {
+            if (!(segments.get(i) instanceof PrimitiveSegment primitive)) {
+                continue;
+            }
+            if (Flags.primitiveCompositionAbsoluteDelay()) {
+                // Primitive support checks introduced by this feature
+                if (!info.isPrimitiveSupported(primitive.getPrimitiveId())) {
+                    return false;
+                }
+            } else {
+                // Delay type support not available without this feature
+                if ((primitive.getDelayType() != PrimitiveSegment.DEFAULT_DELAY_TYPE)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java b/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
index ad44227..a8c4ac8 100644
--- a/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
+++ b/services/core/java/com/android/server/vibrator/SplitPwleSegmentsAdapter.java
@@ -44,7 +44,7 @@
             // The vibrator does not have PWLE v2 capability, so keep the segments unchanged.
             return repeatIndex;
         }
-        int maxPwleDuration = info.getMaxEnvelopeEffectDurationMillis();
+        int maxPwleDuration = (int) info.getMaxEnvelopeEffectDurationMillis();
         if (maxPwleDuration <= 0) {
             // No limit set to PWLE primitive duration.
             return repeatIndex;
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 07478e3..9e75cf2 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -37,8 +37,11 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 import java.util.NoSuchElementException;
 
@@ -60,6 +63,9 @@
          * used for another vibration.
          */
         void onSessionReleased(long sessionId);
+
+        /** Request the manager to trigger a vibration within this session. */
+        void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration vibration);
     }
 
     private final Object mLock = new Object();
@@ -71,7 +77,9 @@
     private final IVibrationSessionCallback mCallback;
     private final CallerInfo mCallerInfo;
     private final VibratorManagerHooks mManagerHooks;
+    private final DeviceAdapter mDeviceAdapter;
     private final Handler mHandler;
+    private final List<DebugInfo> mVibrations = new ArrayList<>();
 
     @GuardedBy("mLock")
     private Status mStatus = Status.RUNNING;
@@ -83,24 +91,28 @@
     private long mEndUptime;
     @GuardedBy("mLock")
     private long mEndTime; // for debugging
+    @GuardedBy("mLock")
+    private VibrationStepConductor mConductor;
 
     VendorVibrationSession(@NonNull CallerInfo callerInfo, @NonNull Handler handler,
-            @NonNull VibratorManagerHooks managerHooks, @NonNull int[] vibratorIds,
+            @NonNull VibratorManagerHooks managerHooks, @NonNull DeviceAdapter deviceAdapter,
             @NonNull IVibrationSessionCallback callback) {
         mCreateUptime = SystemClock.uptimeMillis();
         mCreateTime = System.currentTimeMillis();
-        mVibratorIds = vibratorIds;
+        mVibratorIds = deviceAdapter.getAvailableVibratorIds();
         mHandler = handler;
         mCallback = callback;
         mCallerInfo = callerInfo;
         mManagerHooks = managerHooks;
+        mDeviceAdapter = deviceAdapter;
         CancellationSignal.fromTransport(mCancellationSignal).setOnCancelListener(this);
     }
 
     @Override
     public void vibrate(CombinedVibration vibration, String reason) {
-        // TODO(b/345414356): implement vibration support
-        throw new UnsupportedOperationException("Vendor session vibrations not yet implemented");
+        CallerInfo vibrationCallerInfo = new CallerInfo(mCallerInfo.attrs, mCallerInfo.uid,
+                mCallerInfo.deviceId, mCallerInfo.opPkg, reason);
+        mManagerHooks.vibrate(mSessionId, vibrationCallerInfo, vibration);
     }
 
     @Override
@@ -146,7 +158,7 @@
     public DebugInfo getDebugInfo() {
         synchronized (mLock) {
             return new DebugInfoImpl(mStatus, mCallerInfo, mCreateUptime, mCreateTime, mStartTime,
-                    mEndUptime, mEndTime);
+                    mEndUptime, mEndTime, mVibrations);
         }
     }
 
@@ -200,12 +212,12 @@
 
     @Override
     public void notifyVibratorCallback(int vibratorId, long vibrationId) {
-        // TODO(b/345414356): implement vibration support
+        // Ignore it, the session vibration playback doesn't depend on HAL timings
     }
 
     @Override
     public void notifySyncedVibratorsCallback(long vibrationId) {
-        // TODO(b/345414356): implement vibration support
+        // Ignore it, the session vibration playback doesn't depend on HAL timings
     }
 
     @Override
@@ -214,8 +226,9 @@
             // If end was not requested then the HAL has cancelled the session.
             maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON);
             maybeSetStatusToRequestedLocked();
+            clearVibrationConductor();
         }
-        mManagerHooks.onSessionReleased(mSessionId);
+        mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
     }
 
     @Override
@@ -228,7 +241,8 @@
                     /* includeDate= */ true))
                     + ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
                     + ", callerInfo: " + mCallerInfo
-                    + ", vibratorIds: " + Arrays.toString(mVibratorIds);
+                    + ", vibratorIds: " + Arrays.toString(mVibratorIds)
+                    + ", vibrations: " + mVibrations;
         }
     }
 
@@ -254,6 +268,13 @@
         return mVibratorIds;
     }
 
+    @VisibleForTesting
+    public List<DebugInfo> getVibrations() {
+        synchronized (mLock) {
+            return new ArrayList<>(mVibrations);
+        }
+    }
+
     public ICancellationSignal getCancellationSignal() {
         return mCancellationSignal;
     }
@@ -278,7 +299,39 @@
         }
         if (isAlreadyEnded) {
             // Session already ended, make sure we end it in the HAL.
-            mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true);
+            mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true));
+        }
+    }
+
+    public void notifyVibrationAttempt(DebugInfo vibrationDebugInfo) {
+        mVibrations.add(vibrationDebugInfo);
+    }
+
+    @Nullable
+    public VibrationStepConductor clearVibrationConductor() {
+        synchronized (mLock) {
+            VibrationStepConductor conductor = mConductor;
+            if (conductor != null) {
+                mVibrations.add(conductor.getVibration().getDebugInfo());
+            }
+            mConductor = null;
+            return conductor;
+        }
+    }
+
+    public DeviceAdapter getDeviceAdapter() {
+        return mDeviceAdapter;
+    }
+
+    public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) {
+        synchronized (mLock) {
+            if (mConductor != null) {
+                Slog.d(TAG, "Vibration session still dispatching previous vibration,"
+                        + " new vibration ignored");
+                return false;
+            }
+            mConductor = conductor;
+            return true;
         }
     }
 
@@ -296,7 +349,7 @@
             }
         }
         if (shouldTriggerSessionHook) {
-            mManagerHooks.endSession(mSessionId, shouldAbort);
+            mHandler.post(() ->  mManagerHooks.endSession(mSessionId, shouldAbort));
         }
     }
 
@@ -309,6 +362,11 @@
         mEndStatusRequest = status;
         mEndTime = System.currentTimeMillis();
         mEndUptime = SystemClock.uptimeMillis();
+        if (mConductor != null) {
+            // Vibration is being dispatched when session end was requested, cancel it.
+            mConductor.notifyCancelled(new Vibration.EndInfo(status),
+                    /* immediate= */ status != Status.FINISHED);
+        }
         if (isStarted()) {
             // Only trigger "finishing" callback if session started.
             // Run client callback in separate thread.
@@ -377,6 +435,7 @@
     static final class DebugInfoImpl implements VibrationSession.DebugInfo {
         private final Status mStatus;
         private final CallerInfo mCallerInfo;
+        private final List<DebugInfo> mVibrations;
 
         private final long mCreateUptime;
         private final long mCreateTime;
@@ -385,7 +444,7 @@
         private final long mDurationMs;
 
         DebugInfoImpl(Status status, CallerInfo callerInfo, long createUptime, long createTime,
-                long startTime, long endUptime, long endTime) {
+                long startTime, long endUptime, long endTime, List<DebugInfo> vibrations) {
             mStatus = status;
             mCallerInfo = callerInfo;
             mCreateUptime = createUptime;
@@ -393,6 +452,7 @@
             mStartTime = startTime;
             mEndTime = endTime;
             mDurationMs = endUptime > 0 ? endUptime - createUptime : -1;
+            mVibrations = vibrations == null ? new ArrayList<>() : new ArrayList<>(vibrations);
         }
 
         @Override
@@ -418,6 +478,9 @@
 
         @Override
         public void logMetrics(VibratorFrameworkStatsLogger statsLogger) {
+            for (DebugInfo vibration : mVibrations) {
+                vibration.logMetrics(statsLogger);
+            }
         }
 
         @Override
@@ -448,6 +511,14 @@
             pw.println("endTime = " + (mEndTime == 0 ? null
                     : formatTime(mEndTime, /*includeDate=*/ true)));
             pw.println("callerInfo = " + mCallerInfo);
+
+            pw.println("vibrations:");
+            pw.increaseIndent();
+            for (DebugInfo vibration : mVibrations) {
+                vibration.dump(pw);
+            }
+            pw.decreaseIndent();
+
             pw.decreaseIndent();
         }
 
@@ -477,6 +548,12 @@
                     " | %s (uid=%d, deviceId=%d) | reason: %s",
                     mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.deviceId, mCallerInfo.reason);
             pw.println(timingsStr + paramStr + audioUsageStr + callerStr);
+
+            pw.increaseIndent();
+            for (DebugInfo vibration : mVibrations) {
+                vibration.dumpCompact(pw);
+            }
+            pw.decreaseIndent();
         }
 
         @Override
@@ -487,7 +564,8 @@
                     /* includeDate= */ true))
                     + ", durationMs: " + mDurationMs
                     + ", status: " + mStatus.name().toLowerCase(Locale.ROOT)
-                    + ", callerInfo: " + mCallerInfo;
+                    + ", callerInfo: " + mCallerInfo
+                    + ", vibrations: " + mVibrations;
         }
     }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 6a4790d..1e20deb 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -69,6 +69,7 @@
     // Used within steps.
     public final VibrationSettings vibrationSettings;
     public final VibrationThread.VibratorManagerHooks vibratorManagerHooks;
+    public final boolean isInSession;
 
     private final DeviceAdapter mDeviceAdapter;
     private final VibrationScaler mVibrationScaler;
@@ -105,12 +106,13 @@
     private int mRemainingStartSequentialEffectSteps;
     private int mSuccessfulVibratorOnSteps;
 
-    VibrationStepConductor(HalVibration vib, VibrationSettings vibrationSettings,
-            DeviceAdapter deviceAdapter, VibrationScaler vibrationScaler,
-            VibratorFrameworkStatsLogger statsLogger,
+    VibrationStepConductor(HalVibration vib, boolean isInSession,
+            VibrationSettings vibrationSettings, DeviceAdapter deviceAdapter,
+            VibrationScaler vibrationScaler, VibratorFrameworkStatsLogger statsLogger,
             CompletableFuture<Void> requestVibrationParamsFuture,
             VibrationThread.VibratorManagerHooks vibratorManagerHooks) {
         this.mVibration = vib;
+        this.isInSession = isInSession;
         this.vibrationSettings = vibrationSettings;
         this.mDeviceAdapter = deviceAdapter;
         mVibrationScaler = vibrationScaler;
@@ -286,6 +288,9 @@
         if (nextStep == null) {
             return true;  // Finished
         }
+        if (isInSession) {
+            return true;  // Don't wait to play session vibration steps
+        }
         long waitMillis = nextStep.calculateWaitTime();
         if (waitMillis <= 0) {
             return true;  // Regular step ready
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 4764481..cc163db 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -106,7 +106,7 @@
     private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
     private static final String VIBRATOR_CONTROL_SERVICE =
             "android.frameworks.vibrator.IVibratorControlService/default";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
             new VibrationAttributes.Builder().build();
     private static final int ATTRIBUTES_ALL_BYPASS_FLAGS =
@@ -610,6 +610,11 @@
             logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_ERROR_TOKEN);
             return null;
         }
+        enforceUpdateAppOpsStatsPermission(uid);
+        if (!isEffectValid(effect)) {
+            logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED);
+            return null;
+        }
         if (effect.hasVendorEffects()) {
             if (!Flags.vendorVibrationEffects()) {
                 Slog.e(TAG, "vibrate; vendor effects feature disabled");
@@ -622,11 +627,6 @@
                 return null;
             }
         }
-        enforceUpdateAppOpsStatsPermission(uid);
-        if (!isEffectValid(effect)) {
-            logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED);
-            return null;
-        }
         // Create Vibration.Stats as close to the received request as possible, for tracking.
         SingleVibrationSession session = new SingleVibrationSession(token, callerInfo, effect);
         HalVibration vib = session.getVibration();
@@ -658,6 +658,7 @@
 
             // If not ignored so far then try to start this vibration.
             if (ignoreStatus == null) {
+                // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     if (mCurrentSession != null) {
@@ -703,6 +704,7 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Canceling vibration");
                 }
+                // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     // TODO(b/370948466): investigate why token not checked on external vibrations.
@@ -762,8 +764,18 @@
             vibratorIds = new int[0];
         }
         enforceUpdateAppOpsStatsPermission(uid);
+
+        // Create session with adapter that only uses the session vibrators.
+        SparseArray<VibratorController> sessionVibrators = new SparseArray<>(vibratorIds.length);
+        for (int vibratorId : vibratorIds) {
+            VibratorController controller = mVibrators.get(vibratorId);
+            if (controller != null) {
+                sessionVibrators.put(vibratorId, controller);
+            }
+        }
+        DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, sessionVibrators);
         VendorVibrationSession session = new VendorVibrationSession(callerInfo, mHandler,
-                mVendorVibrationSessionCallbacks, vibratorIds, callback);
+                mVendorVibrationSessionCallbacks, deviceAdapter, callback);
 
         if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
             // Force update of user settings before checking if this vibration effect should
@@ -787,12 +799,15 @@
                 ignoreStatus = Status.IGNORED_UNSUPPORTED;
             }
 
-            // Check if any vibrator ID was requested.
-            if (ignoreStatus == null && vibratorIds.length == 0) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Empty vibrator ids to start session, ignoring request");
+            // Check if vibrator IDs requested are available.
+            if (ignoreStatus == null) {
+                if (vibratorIds.length == 0
+                        || vibratorIds.length != deviceAdapter.getAvailableVibratorIds().length) {
+                    Slog.e(TAG, "Bad vibrator ids to start session, ignoring request."
+                            + " requested=" + Arrays.toString(vibratorIds)
+                            + " available=" + Arrays.toString(mVibratorIds));
+                    ignoreStatus = Status.IGNORED_UNSUPPORTED;
                 }
-                ignoreStatus = Status.IGNORED_UNSUPPORTED;
             }
 
             // Check if user settings or DnD is set to ignore this session.
@@ -810,6 +825,7 @@
             }
 
             if (ignoreStatus == null) {
+                // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     // If not ignored so far then stop ongoing sessions before starting this one.
@@ -839,22 +855,40 @@
     private Status startVendorSessionLocked(VendorVibrationSession session) {
         Trace.traceBegin(TRACE_TAG_VIBRATOR, "startSessionLocked");
         try {
+            long sessionId = session.getSessionId();
+            if (DEBUG) {
+                Slog.d(TAG, "Starting session " + sessionId + " in HAL");
+            }
             if (session.isEnded()) {
                 // Session already ended, possibly cancelled by app cancellation signal.
                 return session.getStatus();
             }
-            if (!session.linkToDeath()) {
-                return Status.IGNORED_ERROR_TOKEN;
+            int mode = startAppOpModeLocked(session.getCallerInfo());
+            switch (mode) {
+                case AppOpsManager.MODE_ALLOWED:
+                    Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0);
+                    // Make sure mCurrentVibration is set while triggering the HAL.
+                    mCurrentSession = session;
+                    if (!session.linkToDeath()) {
+                        mCurrentSession = null;
+                        return Status.IGNORED_ERROR_TOKEN;
+                    }
+                    if (!mNativeWrapper.startSession(sessionId, session.getVibratorIds())) {
+                        Slog.e(TAG, "Error starting session " + sessionId + " on vibrators "
+                                + Arrays.toString(session.getVibratorIds()));
+                        session.unlinkToDeath();
+                        mCurrentSession = null;
+                        return Status.IGNORED_UNSUPPORTED;
+                    }
+                    session.notifyStart();
+                    return null;
+                case AppOpsManager.MODE_ERRORED:
+                    Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+                            + session.getCallerInfo().uid);
+                    return Status.IGNORED_ERROR_APP_OPS;
+                default:
+                    return Status.IGNORED_APP_OPS;
             }
-            if (!mNativeWrapper.startSession(session.getSessionId(), session.getVibratorIds())) {
-                Slog.e(TAG, "Error starting session " + session.getSessionId()
-                        + " on vibrators " + Arrays.toString(session.getVibratorIds()));
-                session.unlinkToDeath();
-                return Status.IGNORED_UNSUPPORTED;
-            }
-            session.notifyStart();
-            mCurrentSession = session;
-            return null;
         } finally {
             Trace.traceEnd(TRACE_TAG_VIBRATOR);
         }
@@ -1045,6 +1079,9 @@
     @GuardedBy("mLock")
     @Nullable
     private Status startVibrationOnThreadLocked(SingleVibrationSession session) {
+        if (DEBUG) {
+            Slog.d(TAG, "Starting vibration " + session.getVibration().id +  " on thread");
+        }
         VibrationStepConductor conductor = createVibrationStepConductor(session.getVibration());
         session.setVibrationConductor(conductor);
         int mode = startAppOpModeLocked(session.getCallerInfo());
@@ -1080,12 +1117,18 @@
             mNextSession = null;
             Status errorStatus = startVibrationOnThreadLocked(session);
             if (errorStatus != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Error starting next vibration " + session.getVibration().id);
+                }
                 endSessionLocked(session, errorStatus);
             }
         } else if (mNextSession instanceof VendorVibrationSession session) {
             mNextSession = null;
             Status errorStatus = startVendorSessionLocked(session);
             if (errorStatus != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Error starting next session " + session.getSessionId());
+                }
                 endSessionLocked(session, errorStatus);
             }
         } // External vibrations cannot be started asynchronously.
@@ -1103,6 +1146,16 @@
     }
 
     private VibrationStepConductor createVibrationStepConductor(HalVibration vib) {
+        return createVibrationStepConductor(vib, mDeviceAdapter, /* isInSession= */ false);
+    }
+
+    private VibrationStepConductor createSessionVibrationStepConductor(HalVibration vib,
+            DeviceAdapter deviceAdapter) {
+        return createVibrationStepConductor(vib, deviceAdapter, /* isInSession= */ true);
+    }
+
+    private VibrationStepConductor createVibrationStepConductor(HalVibration vib,
+            DeviceAdapter deviceAdapter, boolean isInSession) {
         CompletableFuture<Void> requestVibrationParamsFuture = null;
 
         if (Flags.adaptiveHapticsEnabled()
@@ -1114,8 +1167,9 @@
                             mVibrationSettings.getRequestVibrationParamsTimeoutMs());
         }
 
-        return new VibrationStepConductor(vib, mVibrationSettings, mDeviceAdapter, mVibrationScaler,
-                mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks);
+        return new VibrationStepConductor(vib, isInSession, mVibrationSettings,
+                deviceAdapter, mVibrationScaler, mFrameworkStatsLogger,
+                requestVibrationParamsFuture, mVibrationThreadCallbacks);
     }
 
     private Status startVibrationOnInputDevicesLocked(HalVibration vib) {
@@ -1135,18 +1189,15 @@
 
     private void logAndRecordVibrationAttempt(@Nullable CombinedVibration effect,
             CallerInfo callerInfo, Status status) {
-        logAndRecordVibration(
-                new Vibration.DebugInfoImpl(status, callerInfo,
-                        VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(),
-                        effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
-                        VibrationScaler.ADAPTIVE_SCALE_NONE));
+        logAndRecordVibration(createVibrationAttemptDebugInfo(effect, callerInfo, status));
     }
 
     private void logAndRecordSessionAttempt(CallerInfo callerInfo, Status status) {
         logAndRecordVibration(
                 new VendorVibrationSession.DebugInfoImpl(status, callerInfo,
                         SystemClock.uptimeMillis(), System.currentTimeMillis(),
-                        /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0));
+                        /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0,
+                        /* vibrations= */ null));
     }
 
     private void logAndRecordVibration(DebugInfo info) {
@@ -1155,6 +1206,14 @@
         mVibratorManagerRecords.record(info);
     }
 
+    private DebugInfo createVibrationAttemptDebugInfo(@Nullable CombinedVibration effect,
+            CallerInfo callerInfo, Status status) {
+        return new Vibration.DebugInfoImpl(status, callerInfo,
+                VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(),
+                effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
+                VibrationScaler.ADAPTIVE_SCALE_NONE);
+    }
+
     private void logVibrationStatus(int uid, VibrationAttributes attrs, Status status) {
         switch (status) {
             case IGNORED_BACKGROUND:
@@ -1765,25 +1824,35 @@
             Trace.traceBegin(TRACE_TAG_VIBRATOR, "onVibrationThreadReleased");
             try {
                 synchronized (mLock) {
-                    if (!(mCurrentSession instanceof SingleVibrationSession session)) {
-                        if (Build.IS_DEBUGGABLE) {
-                            Slog.wtf(TAG, "VibrationSession invalid on vibration thread release."
-                                    + " currentSession=" + mCurrentSession);
+                    if (mCurrentSession instanceof SingleVibrationSession session) {
+                        if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) {
+                            Slog.wtf(TAG, TextUtils.formatSimple(
+                                    "VibrationId mismatch on vibration thread release."
+                                            + " expected=%d, released=%d",
+                                    session.getVibration().id, vibrationId));
                         }
-                        // Only single vibration sessions are ended by thread being released. Abort.
-                        return;
+                        finishAppOpModeLocked(mCurrentSession.getCallerInfo());
+                        clearCurrentSessionLocked();
+                        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+                        // Start next vibration if it's waiting for the thread.
+                        maybeStartNextSessionLocked();
+                    } else if (mCurrentSession instanceof VendorVibrationSession session) {
+                        VibrationStepConductor conductor = session.clearVibrationConductor();
+                        if (Build.IS_DEBUGGABLE) {
+                            if (conductor == null) {
+                                Slog.wtf(TAG, "Vendor session without ongoing vibration on"
+                                        + " thread release. currentSession=" + mCurrentSession);
+                            } else if (conductor.getVibration().id != vibrationId) {
+                                Slog.wtf(TAG, TextUtils.formatSimple(
+                                        "VibrationId mismatch on vibration thread release."
+                                                + " expected=%d, released=%d",
+                                        conductor.getVibration().id, vibrationId));
+                            }
+                        }
+                    } else if (Build.IS_DEBUGGABLE) {
+                        Slog.wtf(TAG, "VibrationSession invalid on vibration thread release."
+                                + " currentSession=" + mCurrentSession);
                     }
-                    if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) {
-                        Slog.wtf(TAG, TextUtils.formatSimple(
-                                "VibrationId mismatch on vibration thread release."
-                                        + " expected=%d, released=%d",
-                                session.getVibration().id, vibrationId));
-                    }
-                    finishAppOpModeLocked(mCurrentSession.getCallerInfo());
-                    clearCurrentSessionLocked();
-                    Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
-                    // Start next vibration if it's waiting for the thread.
-                    maybeStartNextSessionLocked();
                 }
             } finally {
                 Trace.traceEnd(TRACE_TAG_VIBRATOR);
@@ -1838,6 +1907,86 @@
             implements VendorVibrationSession.VibratorManagerHooks {
 
         @Override
+        public void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration effect) {
+            if (DEBUG) {
+                Slog.d(TAG, "Vibration session " + sessionId + " vibration requested");
+            }
+            Trace.traceBegin(TRACE_TAG_VIBRATOR, "sessionVibrate");
+            try {
+                synchronized (mLock) {
+                    if (!(mCurrentSession instanceof VendorVibrationSession session)) {
+                        if (Build.IS_DEBUGGABLE) {
+                            Slog.wtf(TAG, "VibrationSession invalid on session vibrate."
+                                    + " currentSession=" + mCurrentSession);
+                        }
+                        // Only vendor vibration sessions can handle this call. Abort.
+                        return;
+                    }
+                    if (session.getSessionId() != sessionId) {
+                        if (Build.IS_DEBUGGABLE) {
+                            Slog.wtf(TAG, TextUtils.formatSimple(
+                                    "SessionId mismatch on vendor vibration session vibrate."
+                                            + " expected=%d, released=%d",
+                                    session.getSessionId(), sessionId));
+                        }
+                        // Only the ongoing vendor vibration sessions can handle this call. Abort.
+                        return;
+                    }
+                    if (session.wasEndRequested()) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "session vibrate; session is ending, vibration ignored");
+                        }
+                        session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+                                callerInfo, Status.IGNORED_ERROR_SCHEDULING));
+                        return;
+                    }
+                    if (!isEffectValid(effect)) {
+                        session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+                                callerInfo, Status.IGNORED_UNSUPPORTED));
+                        return;
+                    }
+                    if (effect.getDuration() == Long.MAX_VALUE) {
+                        // Repeating effects cannot be played by the service in a session.
+                        session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+                                callerInfo, Status.IGNORED_UNSUPPORTED));
+                        return;
+                    }
+                    // Create Vibration.Stats as close to the request as possible, for tracking.
+                    HalVibration vib = new HalVibration(callerInfo, effect);
+                    vib.fillFallbacks(mVibrationSettings::getFallbackEffect);
+
+                    if (callerInfo.attrs.isFlagSet(
+                            VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+                        // Force update of user settings before checking if this vibration effect
+                        // should be ignored or scaled.
+                        mVibrationSettings.update();
+                    }
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "Starting vibrate for vibration " + vib.id
+                                + " in session " + sessionId);
+                    }
+
+                    VibrationStepConductor conductor =
+                            createSessionVibrationStepConductor(vib, session.getDeviceAdapter());
+                    if (session.maybeSetVibrationConductor(conductor)) {
+                        if (!mVibrationThread.runVibrationOnVibrationThread(conductor)) {
+                            // Shouldn't happen. The method call already logs.
+                            vib.end(new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING));
+                            session.clearVibrationConductor(); // Rejected by thread, clear it.
+                        }
+                    } else {
+                        // Cannot set vibration in session, log failed attempt.
+                        session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect,
+                                callerInfo, Status.IGNORED_ERROR_SCHEDULING));
+                    }
+                }
+            } finally {
+                Trace.traceEnd(TRACE_TAG_VIBRATOR);
+            }
+        }
+
+        @Override
         public void endSession(long sessionId, boolean shouldAbort) {
             if (DEBUG) {
                 Slog.d(TAG, "Vibration session " + sessionId
@@ -1873,6 +2022,12 @@
                                         + " expected=%d, released=%d",
                                 session.getSessionId(), sessionId));
                     }
+                    // Make sure all controllers in session are reset after session ended.
+                    // This will update the vibrator state to isVibrating = false for listeners.
+                    for (int vibratorId : session.getVibratorIds()) {
+                        mVibrators.get(vibratorId).off();
+                    }
+                    finishAppOpModeLocked(mCurrentSession.getCallerInfo());
                     clearCurrentSessionLocked();
                     // Start next vibration if it's waiting for the HAL session to be over.
                     maybeStartNextSessionLocked();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1c11c67..c6e6e76 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2538,6 +2538,19 @@
                 }
             }
             if (!activityAllDrawn && !isActivityHome) {
+                // Only check the special case of a fragment host task because the starting window
+                // may not be visible if the client organizer delays the transition ready.
+                if (task.mTaskFragmentHostProcessName != null) {
+                    // It may be launched from a task trampoline that already has a starting window.
+                    // Return NONE because 2 consecutive splashes may not look smooth in visual.
+                    final Task prevTask = task.getParent().getTaskBelow(task);
+                    if (prevTask != null) {
+                        final ActivityRecord prevTaskTop = prevTask.getTopMostActivity();
+                        if (prevTaskTop != null && prevTaskTop.hasStartingWindow()) {
+                            return STARTING_WINDOW_TYPE_NONE;
+                        }
+                    }
+                }
                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
             }
         }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 9f40bed..25fdf89 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -17,8 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_DIMMER;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -44,7 +42,8 @@
      */
     private final WindowContainer<?> mHost;
 
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "Dimmer" : TAG_WM;
+    private static final String TAG = "WindowManagerDimmer";
+
     DimState mDimState;
     final DimmerAnimationHelper.AnimationAdapterFactory mAnimationAdapterFactory;
 
@@ -69,9 +68,10 @@
 
         DimState() {
             mHostContainer = mHost;
-            mAnimationHelper = new DimmerAnimationHelper(mAnimationAdapterFactory);
+            mAnimationHelper = new DimmerAnimationHelper(mHost, mAnimationAdapterFactory);
             try {
                 mDimSurface = makeDimLayer();
+                EventLogTags.writeWmDimCreated(mHost.getName(), mDimSurface.getLayerId());
             } catch (Surface.OutOfResourcesException e) {
                 Log.w(TAG, "OutOfResourcesException creating dim surface");
             }
@@ -102,6 +102,11 @@
          * Prepare the dim for the exit animation
          */
         void exit(@NonNull SurfaceControl.Transaction t) {
+            EventLogTags.writeWmDimExit(mDimState.mDimSurface.getLayerId(),
+                    mDimState.mLastDimmingWindow != null
+                            ? mDimState.mLastDimmingWindow.getName() : "-",
+                    mDimState.mHostContainer.isVisible() ? 1 : 0,
+                    mAnimateExit ? 0 : 1);
             if (!mAnimateExit) {
                 remove(t);
             } else {
@@ -111,8 +116,10 @@
         }
 
         void remove(@NonNull SurfaceControl.Transaction t) {
+            EventLogTags.writeWmDimCancelAnim(mDimSurface.getLayerId(), "ready to remove");
             mAnimationHelper.stopCurrentAnimation(mDimSurface);
             if (mDimSurface.isValid()) {
+                EventLogTags.writeWmDimRemoved(mDimSurface.getLayerId());
                 t.remove(mDimSurface);
                 ProtoLog.d(WM_DEBUG_DIMMER,
                         "Removing dim surface %s on transaction %s", this, t);
@@ -126,6 +133,13 @@
             return "Dimmer#DimState with host=" + mHostContainer + ", surface=" + mDimSurface;
         }
 
+
+        String reasonForRemoving() {
+            return mLastDimmingWindow != null ? mLastDimmingWindow
+                    + " is dimming but host " + mHostContainer + " is not visibleRequested"
+                    : " no one is dimming";
+        }
+
         /**
          * Set the parameters to prepare the dim to be relative parented to the dimming container
          */
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index 0d0e548..1d447dd 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -76,9 +76,11 @@
             return mDimmingContainer != null && mDimmingContainer == other.mDimmingContainer;
         }
 
-        void inheritPropertiesFromAnimation(@NonNull AnimationSpec anim) {
-            mAlpha = anim.mCurrentAlpha;
-            mBlurRadius = anim.mCurrentBlur;
+        void inheritPropertiesFromAnimation(@Nullable AnimationSpec anim) {
+            if (anim != null) {
+                mAlpha = anim.mCurrentAlpha;
+                mBlurRadius = anim.mCurrentBlur;
+            }
         }
 
         @Override
@@ -92,11 +94,13 @@
     private final Change mRequestedProperties = new Change();
     private AnimationSpec mAlphaAnimationSpec;
 
+    private final SurfaceAnimationRunner mSurfaceAnimationRunner;
     private final AnimationAdapterFactory mAnimationAdapterFactory;
     private AnimationAdapter mLocalAnimationAdapter;
 
-    DimmerAnimationHelper(AnimationAdapterFactory animationFactory) {
+    DimmerAnimationHelper(WindowContainer<?> host, AnimationAdapterFactory animationFactory) {
         mAnimationAdapterFactory = animationFactory;
+        mSurfaceAnimationRunner = host.mWmService.mSurfaceAnimationRunner;
     }
 
     void setExitParameters() {
@@ -160,6 +164,7 @@
         }
 
         if (!startProperties.hasSameVisualProperties(mRequestedProperties)) {
+            EventLogTags.writeWmDimCancelAnim(dim.mDimSurface.getLayerId(), "new target values");
             stopCurrentAnimation(dim.mDimSurface);
 
             if (dim.mSkipAnimation
@@ -189,13 +194,15 @@
         ProtoLog.v(WM_DEBUG_DIMMER, "Starting animation on %s", dim);
         mAlphaAnimationSpec = getRequestedAnimationSpec(from, to);
         mLocalAnimationAdapter = mAnimationAdapterFactory.get(mAlphaAnimationSpec,
-                dim.mHostContainer.mWmService.mSurfaceAnimationRunner);
+                mSurfaceAnimationRunner);
 
         float targetAlpha = to.mAlpha;
+        EventLogTags.writeWmDimAnimate(dim.mDimSurface.getLayerId(), targetAlpha, to.mBlurRadius);
 
         mLocalAnimationAdapter.startAnimation(dim.mDimSurface, t,
                 ANIMATION_TYPE_DIMMER, /* finishCallback */ (type, animator) -> {
                     synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
+                        EventLogTags.writeWmDimFinishAnim(dim.mDimSurface.getLayerId());
                         SurfaceControl.Transaction finishTransaction =
                                 dim.mHostContainer.getSyncTransaction();
                         setCurrentAlphaBlur(dim, finishTransaction);
@@ -208,18 +215,12 @@
                 });
     }
 
-    private boolean isAnimating() {
-        return mAlphaAnimationSpec != null;
-    }
-
     void stopCurrentAnimation(@NonNull SurfaceControl surface) {
-        if (mLocalAnimationAdapter != null && isAnimating()) {
-            // Save the current animation progress and cancel the animation
-            mCurrentProperties.inheritPropertiesFromAnimation(mAlphaAnimationSpec);
-            mLocalAnimationAdapter.onAnimationCancelled(surface);
-            mLocalAnimationAdapter = null;
-            mAlphaAnimationSpec = null;
-        }
+        // (If animating) save the current animation progress and cancel the animation
+        mCurrentProperties.inheritPropertiesFromAnimation(mAlphaAnimationSpec);
+        mSurfaceAnimationRunner.onAnimationCancelled(surface);
+        mLocalAnimationAdapter = null;
+        mAlphaAnimationSpec = null;
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index cc2249de..9d66886 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -87,3 +87,16 @@
 
 # Entering pip called
 38000 wm_enter_pip (User|1|5),(Token|1|5),(Component Name|3),(is Auto Enter|3)
+
+# Dim layer is created
+38200 wm_dim_created (Host|3),(Surface|1)
+# Dimmer is ready for removal
+38201 wm_dim_exit (Surface|1),(dimmingWindow|3),(hostIsVisible|1),(removeImmediately|1)
+# Dimmer is starting an animation
+38202 wm_dim_animate (Surface|1, (toAlpha|5), (toBlur|5))
+# Dimmer animation is cancelled
+38203 wm_dim_cancel_anim (Surface|1),(reason|3)
+# Dimmer animation is finished
+38204 wm_dim_finish_anim (Surface|1)
+# Dimmer removing surface
+38205 wm_dim_removed (Surface|1)
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 4b2d454..cf145f9 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -228,13 +228,11 @@
             changed |= provider.updateClientVisibility(caller,
                     isImeProvider ? statsToken : null);
         }
-        if (!android.view.inputmethod.Flags.refactorInsetsController()) {
-            if (changed) {
-                notifyInsetsChanged();
-                mDisplayContent.updateSystemGestureExclusion();
+        if (changed) {
+            notifyInsetsChanged();
+            mDisplayContent.updateSystemGestureExclusion();
 
-                mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
-            }
+            mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 9de96f14..81a04af 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -326,9 +326,12 @@
         ProtoLog.i(WM_DEBUG_TASKS, "Setting frozen recents task list");
 
         // Always update the reordering time when this is called to ensure that the timeout
-        // is reset
+        // is reset.  Extend this duration when running in tests.
+        final long timeout = ActivityManager.isRunningInUserTestHarness()
+                ? mFreezeTaskListTimeoutMs * 10
+                : mFreezeTaskListTimeoutMs;
         mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable);
-        mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs);
+        mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, timeout);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6707a27..f50417d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2856,7 +2856,10 @@
 
     void prepareForShutdown() {
         for (int i = 0; i < getChildCount(); i++) {
-            createSleepToken("shutdown", getChildAt(i).mDisplayId);
+            final int displayId = getChildAt(i).mDisplayId;
+            mWindowManager.mSnapshotController.mTaskSnapshotController
+                    .snapshotForShutdown(displayId);
+            createSleepToken("shutdown", displayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1bb4c41..0f66b93 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -706,6 +706,10 @@
                 win.setRequestedVisibleTypes(requestedVisibleTypes);
                 win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
                         imeStatsToken);
+                final Task task = win.getTask();
+                if (task != null) {
+                    task.dispatchTaskInfoChangedIfNeeded(/* forced= */ true);
+                }
             } else {
                 EmbeddedWindowController.EmbeddedWindow embeddedWindow = null;
                 if (android.view.inputmethod.Flags.refactorInsetsController()) {
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index 1c8c245..bd8e8f4 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -64,6 +64,7 @@
     private boolean mStarted;
     private final Object mLock = new Object();
     private final UserManagerInternal mUserManagerInternal;
+    private boolean mShutdown;
 
     SnapshotPersistQueue() {
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -101,6 +102,16 @@
         }
     }
 
+    /**
+     * Write out everything in the queue because of shutdown.
+     */
+    void shutdown() {
+        synchronized (mLock) {
+            mShutdown = true;
+            mLock.notifyAll();
+        }
+    }
+
     @VisibleForTesting
     void waitForQueueEmpty() {
         while (true) {
@@ -193,7 +204,9 @@
                     if (isReadyToWrite) {
                         next.write();
                     }
-                    SystemClock.sleep(DELAY_MS);
+                    if (!mShutdown) {
+                        SystemClock.sleep(DELAY_MS);
+                    }
                 }
                 synchronized (mLock) {
                     final boolean writeQueueEmpty = mWriteQueue.isEmpty();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 352dc52..dbc3b76c2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3436,7 +3436,8 @@
         info.isSleeping = shouldSleepActivities();
         info.isTopActivityTransparent = top != null && !top.fillsParent();
         info.lastNonFullscreenBounds = topTask.mLastNonFullscreenBounds;
-        final WindowState windowState = top != null ? top.findMainWindow() : null;
+        final WindowState windowState = top != null
+                ? top.findMainWindow(/* includeStartingApp= */ false) : null;
         info.requestedVisibleTypes = (windowState != null && Flags.enableFullyImmersiveInDesktop())
                 ? windowState.getRequestedVisibleTypes() : WindowInsets.Type.defaultVisible();
         AppCompatUtils.fillAppCompatTaskInfo(this, info, top);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 1f82cdb..9fe3f756 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -307,6 +307,28 @@
     }
 
     /**
+     * Record task snapshots before shutdown.
+     */
+    void snapshotForShutdown(int displayId) {
+        if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) {
+            return;
+        }
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
+        if (displayContent == null) {
+            return;
+        }
+        displayContent.forAllLeafTasks(task -> {
+            if (task.isVisible() && !task.isActivityTypeHome()) {
+                final TaskSnapshot snapshot = captureSnapshot(task);
+                if (snapshot != null) {
+                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                }
+            }
+        }, true /* traverseTopToBottom */);
+        mPersister.mSnapshotPersistQueue.shutdown();
+    }
+
+    /**
      * Called when screen is being turned off.
      */
     void screenTurningOff(int displayId, ScreenOffListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 88b2d22..8268cae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1022,12 +1022,12 @@
                 return;
             }
 
-            final boolean disableSecureWindows;
+            boolean disableSecureWindows;
             try {
                 disableSecureWindows = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                         Settings.Secure.DISABLE_SECURE_WINDOWS, 0) != 0;
             } catch (Settings.SettingNotFoundException e) {
-                return;
+                disableSecureWindows = false;
             }
             if (mDisableSecureWindows == disableSecureWindows) {
                 return;
@@ -10233,6 +10233,17 @@
         }
     }
 
+    /**
+     * Resets the spatial ordering of recents for testing purposes.
+     */
+    void resetFreezeRecentTaskListReordering() {
+        if (!checkCallingPermission(permission.MANAGE_ACTIVITY_TASKS,
+                "resetFreezeRecentTaskListReordering()")) {
+            throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
+        }
+        mAtmService.getRecentTasks().resetFreezeTaskListReorderingOnTimeout();
+    }
+
     @Override
     public void registerTrustedPresentationListener(IBinder window,
             ITrustedPresentationListener listener,
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 21ed8d7..fe2bcc7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -161,6 +161,8 @@
                     return runReset(pw);
                 case "disable-blur":
                     return runSetBlurDisabled(pw);
+                case "reset-freeze-recent-tasks":
+                    return runResetFreezeRecentTaskListReordering(pw);
                 case "set-display-windowing-mode":
                     return runSetDisplayWindowingMode(pw);
                 case "get-display-windowing-mode":
@@ -275,6 +277,11 @@
         return 0;
     }
 
+    private int runResetFreezeRecentTaskListReordering(PrintWriter pw) throws RemoteException {
+        mInternal.resetFreezeRecentTaskListReordering();
+        return 0;
+    }
+
     private void printInitialDisplayDensity(PrintWriter pw , int displayId) {
         try {
             final int initialDensity = mInterface.getInitialDisplayDensity(displayId);
@@ -1592,6 +1599,8 @@
         printLetterboxHelp(pw);
         printMultiWindowConfigHelp(pw);
 
+        pw.println("  reset-freeze-recent-tasks");
+        pw.println("    Resets the spatial ordering of the recent tasks list");
         pw.println("  set-display-windowing-mode [-d DISPLAY_ID] [mode_id]");
         pw.println("    As mode_id, use " + WINDOWING_MODE_UNDEFINED + " for undefined, "
                 + WINDOWING_MODE_FREEFORM + " for freeform, " + WINDOWING_MODE_FULLSCREEN + " for"
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ead1282..0918965 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -788,7 +788,9 @@
                 deferResume = false;
                 // Already calls ensureActivityConfig
                 mService.mRootWindowContainer.ensureActivitiesVisible();
-                mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
+                if (!mService.mRootWindowContainer.resumeFocusedTasksTopActivities()) {
+                    mService.mTaskSupervisor.updateTopResumedActivityIfNeeded("endWCT-effects");
+                }
             } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
                 for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
                     haveConfigChanges.valueAt(i).forAllActivities(r -> {
@@ -886,7 +888,8 @@
 
         if (windowingMode > -1) {
             if (mService.isInLockTaskMode()
-                    && WindowConfiguration.inMultiWindowMode(windowingMode)) {
+                    && WindowConfiguration.inMultiWindowMode(windowingMode)
+                    && !container.isEmbedded()) {
                 Slog.w(TAG, "Dropping unsupported request to set multi-window windowing mode"
                         + " during locked task mode.");
                 return effects;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 079170a..81af78e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2989,15 +2989,7 @@
         return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
     }
 
-    @Override
-    void resolveOverrideConfiguration(Configuration newParentConfig) {
-        super.resolveOverrideConfiguration(newParentConfig);
-        if (mActivityRecord != null) {
-            // Let the activity decide whether to apply the size override.
-            return;
-        }
-        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
-        resolvedConfig.seq = newParentConfig.seq;
+    void applySizeOverride(Configuration newParentConfig, Configuration resolvedConfig) {
         applySizeOverrideIfNeeded(
                 getDisplayContent(),
                 mSession.mProcess.mInfo,
@@ -3380,8 +3372,10 @@
             if (cleanupOnResume) {
                 requestUpdateWallpaperIfNeeded();
             }
-            mDestroying = false;
-            destroyedSomething = true;
+            if (!mHasSurface) {
+                mDestroying = false;
+                destroyedSomething = true;
+            }
 
             // Since mDestroying will affect ActivityRecord#allDrawn, we need to perform another
             // traversal in case we are waiting on this window to start the transition.
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 44e237a..004f406 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -672,6 +672,15 @@
             getResolvedOverrideConfiguration().updateFrom(
                     mFixedRotationTransformState.mRotatedOverrideConfiguration);
         }
+        if (asActivityRecord() == null) {
+            // Let ActivityRecord override the config if there is one. Otherwise, override here.
+            // Resolve WindowToken's configuration by the latest window.
+            final WindowState win = getTopChild();
+            if (win != null) {
+                final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+                win.applySizeOverride(newParentConfig, resolvedConfig);
+            }
+        }
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index b982098..76d16e1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -371,6 +371,9 @@
     }
 
     ActiveAdmin(int userId, boolean permissionBased) {
+        if (Flags.activeAdminCleanup()) {
+            throw new UnsupportedOperationException("permission based admin no longer supported");
+        }
         if (permissionBased == false) {
             throw new IllegalArgumentException("Can only pass true for permissionBased admin");
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 395ea91..c937e10 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -21,6 +21,7 @@
 import android.annotation.UserIdInt;
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.os.FileUtils;
 import android.os.PersistableBundle;
@@ -124,17 +125,18 @@
     final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
     final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
-    // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that
-    // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be
-    // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies
-    // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList
-    // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName.
-    // Instead, use variants of DPMS active admin getters to include the permission-based admin.
+    /**
+     * @deprecated Do not use. Policies set by permission holders must go into DevicePolicyEngine.
+     */
+    @Deprecated
     ActiveAdmin mPermissionBasedAdmin;
 
     // Create or get the permission-based admin. The permission-based admin will not have a
     // DeviceAdminInfo or ComponentName.
     ActiveAdmin createOrGetPermissionBasedAdmin(int userId) {
+        if (Flags.activeAdminCleanup()) {
+            throw new UnsupportedOperationException("permission based admin no longer supported");
+        }
         if (mPermissionBasedAdmin == null) {
             mPermissionBasedAdmin = new ActiveAdmin(userId, /* permissionBased= */ true);
         }
@@ -147,7 +149,7 @@
     // This is the list of component allowed to start lock task mode.
     List<String> mLockTaskPackages = new ArrayList<>();
 
-    /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
+    /** @deprecated moved to DevicePolicyEngine. */
     @Deprecated
     @Nullable
     List<String> mUserControlDisabledPackages;
@@ -280,7 +282,7 @@
                 }
             }
 
-            if (policyData.mPermissionBasedAdmin != null) {
+            if (!Flags.activeAdminCleanup() && policyData.mPermissionBasedAdmin != null) {
                 out.startTag(null, "permission-based-admin");
                 policyData.mPermissionBasedAdmin.writeToXml(out);
                 out.endTag(null, "permission-based-admin");
@@ -521,7 +523,8 @@
                     } catch (RuntimeException e) {
                         Slogf.w(TAG, e, "Failed loading admin %s", name);
                     }
-                } else if ("permission-based-admin".equals(tag)) {
+                } else if (!Flags.activeAdminCleanup() && "permission-based-admin".equals(tag)) {
+
                     ActiveAdmin ap = new ActiveAdmin(policy.mUserId, /* permissionBased= */ true);
                     ap.readFromXml(parser, /* overwritePolicies= */ false);
                     policy.mPermissionBasedAdmin = ap;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index c19c58e..cb333f0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -1236,6 +1236,8 @@
                 }
             }
             for (EnforcingAdmin admin : admins) {
+                // No need to make changes to system enforcing admins.
+                if (admin.isSystemAuthority()) break;
                 if (updatedPackage == null || updatedPackage.equals(admin.getPackageName())) {
                     if (!isPackageInstalled(admin.getPackageName(), userId)) {
                         Slogf.i(TAG, String.format(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d221e8c..6292cbf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -376,6 +376,7 @@
 import android.app.compat.CompatChanges;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
+import android.app.supervision.SupervisionManagerInternal;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.compat.annotation.ChangeId;
@@ -504,6 +505,7 @@
 import com.android.internal.app.LocalePicker;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -715,24 +717,24 @@
         SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.add(Settings.Secure.LOCATION_MODE);
 
         GLOBAL_SETTINGS_ALLOWLIST = new ArraySet<>();
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_ENABLED);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_WIFI_ENABLED);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME_ZONE);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.DATA_ROAMING);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_SLEEP_POLICY);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_MODE);
-        GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_ENABLED);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_WIFI_ENABLED);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME_ZONE);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.DATA_ROAMING);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.USB_MASS_STORAGE_ENABLED);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_SLEEP_POLICY);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.STAY_ON_WHILE_PLUGGED_IN);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
+        GLOBAL_SETTINGS_ALLOWLIST.add(Global.PRIVATE_DNS_MODE);
+        GLOBAL_SETTINGS_ALLOWLIST.add(PRIVATE_DNS_SPECIFIER);
 
         GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>();
-        GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON);
-        GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
-        GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.MODE_RINGER);
-        GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE);
-        GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
+        GLOBAL_SETTINGS_DEPRECATED.add(Global.BLUETOOTH_ON);
+        GLOBAL_SETTINGS_DEPRECATED.add(Global.DEVELOPMENT_SETTINGS_ENABLED);
+        GLOBAL_SETTINGS_DEPRECATED.add(Global.MODE_RINGER);
+        GLOBAL_SETTINGS_DEPRECATED.add(Global.NETWORK_PREFERENCE);
+        GLOBAL_SETTINGS_DEPRECATED.add(Global.WIFI_ON);
 
         SYSTEM_SETTINGS_ALLOWLIST = new ArraySet<>();
         SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS);
@@ -775,7 +777,7 @@
 
     /**
      * Strings logged with {@link
-     * com.android.internal.logging.nano.MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB},
+     * MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB},
      * {@link DevicePolicyEnums#PROVISIONING_ENTRY_POINT_ADB},
      * {@link DevicePolicyEnums#SET_NETWORK_LOGGING_ENABLED} and
      * {@link DevicePolicyEnums#RETRIEVE_NETWORK_LOGS}.
@@ -786,11 +788,11 @@
     /**
      * For admin apps targeting R+, throw when the app sets password requirement
      * that is not taken into account at given quality. For example when quality is set
-     * to {@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't
+     * to {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't
      * make sense to require certain password length. If the intent is to require a password of
      * certain length having at least NUMERIC quality, the admin should first call
-     * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} and only then call
-     * {@link android.app.admin.DevicePolicyManager#setPasswordMinimumLength}.
+     * {@link DevicePolicyManager#setPasswordQuality} and only then call
+     * {@link DevicePolicyManager#setPasswordMinimumLength}.
      *
      * <p>Conversely when an admin app targeting R+ lowers password quality, those
      * requirements that stop making sense are reset to default values.
@@ -801,9 +803,9 @@
 
     /**
      * Admin apps targeting Android R+ may not use
-     * {@link android.app.admin.DevicePolicyManager#setSecureSetting} to change the deprecated
-     * {@link android.provider.Settings.Secure#LOCATION_MODE} setting. Instead they should use
-     * {@link android.app.admin.DevicePolicyManager#setLocationEnabled}.
+     * {@link DevicePolicyManager#setSecureSetting} to change the deprecated
+     * {@link Settings.Secure#LOCATION_MODE} setting. Instead they should use
+     * {@link DevicePolicyManager#setLocationEnabled}.
      */
     @ChangeId
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
@@ -849,7 +851,7 @@
     private @interface CopyAccountStatus {}
 
     /**
-     * Mapping of {@link android.app.admin.DevicePolicyManager.ApplicationExemptionConstants} to
+     * Mapping of {@link DevicePolicyManager.ApplicationExemptionConstants} to
      * corresponding app-ops.
      */
     private static final Map<Integer, String> APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS =
@@ -881,11 +883,11 @@
 
     /**
      * Admin apps targeting Android S+ may not use
-     * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
+     * {@link DevicePolicyManager#setPasswordQuality} to set password quality
      * on the {@code DevicePolicyManager} instance obtained by calling
-     * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
+     * {@link DevicePolicyManager#getParentProfileInstance}.
      * Instead, they should use
-     * {@link android.app.admin.DevicePolicyManager#setRequiredPasswordComplexity} to set
+     * {@link DevicePolicyManager#setRequiredPasswordComplexity} to set
      * coarse-grained password requirements device-wide.
      */
     @ChangeId
@@ -894,7 +896,7 @@
 
     /**
      * For Admin Apps targeting U+
-     * If {@link android.security.IKeyChainService#setGrant} is called with an alias with no
+     * If {@link IKeyChainService#setGrant} is called with an alias with no
      * existing key, throw IllegalArgumentException.
      */
     @ChangeId
@@ -926,6 +928,8 @@
     final UsageStatsManagerInternal mUsageStatsManagerInternal;
     final TelephonyManager mTelephonyManager;
     final RoleManager mRoleManager;
+    final SupervisionManagerInternal mSupervisionManagerInternal;
+
     private final LockPatternUtils mLockPatternUtils;
     private final LockSettingsInternal mLockSettingsInternal;
     private final DeviceAdminServiceController mDeviceAdminServiceController;
@@ -1474,8 +1478,8 @@
                     if (packageName == null || packageName.equals(adminPackage)) {
                         if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
                                 || mIPackageManager.getReceiverInfo(aa.info.getComponent(),
-                                PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                MATCH_DIRECT_BOOT_AWARE
+                                        | MATCH_DIRECT_BOOT_UNAWARE,
                                 userHandle) == null) {
                             Slogf.e(LOG_TAG, String.format(
                                     "Admin package %s not found for user %d, removing active admin",
@@ -1693,7 +1697,7 @@
             return getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
         }
 
-        Context createContextAsUser(UserHandle user) throws PackageManager.NameNotFoundException {
+        Context createContextAsUser(UserHandle user) throws NameNotFoundException {
             final String packageName = mContext.getPackageName();
             return mContext.createPackageContextAsUser(packageName, 0, user);
         }
@@ -2005,25 +2009,25 @@
         }
 
         void settingsGlobalPutStringForUser(String name, String value, int userHandle) {
-            Settings.Global.putStringForUser(mContext.getContentResolver(),
+            Global.putStringForUser(mContext.getContentResolver(),
                     name, value, userHandle);
         }
 
         int settingsGlobalGetInt(String name, int def) {
-            return Settings.Global.getInt(mContext.getContentResolver(), name, def);
+            return Global.getInt(mContext.getContentResolver(), name, def);
         }
 
         @Nullable
         String settingsGlobalGetString(String name) {
-            return Settings.Global.getString(mContext.getContentResolver(), name);
+            return Global.getString(mContext.getContentResolver(), name);
         }
 
         void settingsGlobalPutInt(String name, int value) {
-            Settings.Global.putInt(mContext.getContentResolver(), name, value);
+            Global.putInt(mContext.getContentResolver(), name, value);
         }
 
         void settingsGlobalPutString(String name, String value) {
-            Settings.Global.putString(mContext.getContentResolver(), name, value);
+            Global.putString(mContext.getContentResolver(), name, value);
         }
 
         void settingsSystemPutStringForUser(String name, String value, int userId) {
@@ -2082,6 +2086,11 @@
         boolean isAdminInstalledCaCertAutoApproved() {
             return false;
         }
+
+        @Nullable
+        SupervisionManagerInternal getSupervisionManager() {
+            return LocalServices.getService(SupervisionManagerInternal.class);
+        }
     }
 
     /**
@@ -2113,6 +2122,11 @@
         mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
         mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
         mRoleManager = Objects.requireNonNull(injector.getRoleManager());
+        if (Flags.secondaryLockscreenApiEnabled()) {
+            mSupervisionManagerInternal = injector.getSupervisionManager();
+        } else {
+            mSupervisionManagerInternal = null;
+        }
 
         mLocalService = new LocalService();
         mLockPatternUtils = injector.newLockPatternUtils();
@@ -2234,7 +2248,6 @@
         return Collections.unmodifiableSet(packageNames);
     }
 
-
     private @Nullable String getDefaultRoleHolderPackageName(int resId) {
         String packageNameAndSignature = mContext.getString(resId);
 
@@ -3194,8 +3207,8 @@
                 return mIPackageManager.getReceiverInfo(adminName,
                         GET_META_DATA
                         | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
-                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
+                        | MATCH_DIRECT_BOOT_AWARE
+                        | MATCH_DIRECT_BOOT_UNAWARE, userHandle);
             } catch (RemoteException e) {
                 // shouldn't happen.
                 Slogf.wtf(LOG_TAG, "Error getting receiver info", e);
@@ -3206,9 +3219,9 @@
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
 
-        if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) {
+        if (!BIND_DEVICE_ADMIN.equals(ai.permission)) {
             final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
-                    + permission.BIND_DEVICE_ADMIN;
+                    + BIND_DEVICE_ADMIN;
             Slogf.w(LOG_TAG, message);
             if (throwForMissingPermission &&
                     ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) {
@@ -3966,7 +3979,8 @@
             final int N = admins.size();
             for (int i = 0; i < N; i++) {
                 ActiveAdmin admin = admins.get(i);
-                if ((admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD))
+                if (((!Flags.activeAdminCleanup() && admin.isPermissionBased)
+                        || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD))
                         && admin.passwordExpirationTimeout > 0L
                         && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
                         && admin.passwordExpirationDate > 0L) {
@@ -4399,8 +4413,8 @@
         final ApplicationInfo ai;
         try {
             ai = mInjector.getIPackageManager().getApplicationInfo(packageName,
-                    (PackageManager.MATCH_DIRECT_BOOT_AWARE
-                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
+                    (MATCH_DIRECT_BOOT_AWARE
+                            | MATCH_DIRECT_BOOT_UNAWARE), userHandle);
         } catch (RemoteException e) {
             throw new IllegalStateException(e);
         }
@@ -5563,13 +5577,25 @@
                 caller.getUserId());
         Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller));
 
-        ActiveAdmin activeAdmin = admin.getActiveAdmin();
+        final ActiveAdmin activeAdmin;
+        if (Flags.activeAdminCleanup()) {
+            if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
+                synchronized (getLockObject()) {
+                    activeAdmin = getActiveAdminUncheckedLocked(
+                            admin.getComponentName(), admin.getUserId());
+                }
+            } else {
+                activeAdmin = null;
+            }
+        } else {
+            activeAdmin = admin.getActiveAdmin();
+        }
 
         // We require the caller to explicitly clear any password quality requirements set
         // on the parent DPM instance, to avoid the case where password requirements are
         // specified in the form of quality on the parent but complexity on the profile
         // itself.
-        if (!calledOnParent) {
+        if (activeAdmin != null && !calledOnParent) {
             final boolean hasQualityRequirementsOnParent = activeAdmin.hasParentActiveAdmin()
                     && activeAdmin.getParentActiveAdmin().mPasswordPolicy.quality
                     != PASSWORD_QUALITY_UNSPECIFIED;
@@ -5593,20 +5619,22 @@
         }
 
         mInjector.binderWithCleanCallingIdentity(() -> {
-            // Reset the password policy.
-            if (calledOnParent) {
-                activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy();
-            } else {
-                activeAdmin.mPasswordPolicy = new PasswordPolicy();
+            if (activeAdmin != null) {
+                // Reset the password policy.
+                if (calledOnParent) {
+                    activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy();
+                } else {
+                    activeAdmin.mPasswordPolicy = new PasswordPolicy();
+                }
+                updatePasswordQualityCacheForUserGroup(caller.getUserId());
             }
+
             synchronized (getLockObject()) {
                 updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
             }
-            updatePasswordQualityCacheForUserGroup(caller.getUserId());
             saveSettingsLocked(caller.getUserId());
         });
 
-
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY)
                 .setAdmin(caller.getPackageName())
@@ -5965,7 +5993,7 @@
             Preconditions.checkCallAuthorization(admin != null,
                     "Unauthorized caller cannot call resetPassword.");
             if (getTargetSdk(admin.info.getPackageName(),
-                    userHandle) <= android.os.Build.VERSION_CODES.M) {
+                    userHandle) <= Build.VERSION_CODES.M) {
                 Slogf.e(LOG_TAG, "Device admin can no longer call resetPassword()");
                 return false;
             }
@@ -6115,7 +6143,7 @@
             if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
-                mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+                mInjector.settingsGlobalPutInt(Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
             getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(parentId, timeMs);
         });
@@ -6287,28 +6315,33 @@
         final int callingUserId = caller.getUserId();
         ComponentName adminComponent = null;
         synchronized (getLockObject()) {
-            ActiveAdmin admin;
             // Make sure the caller has any active admin with the right policy or
             // the required permission.
             if (Flags.lockNowCoexistence()) {
-                admin = enforcePermissionsAndGetEnforcingAdmin(
+                EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
                         /* admin= */ null,
                         /* permissions= */ new String[]{MANAGE_DEVICE_POLICY_LOCK, LOCK_DEVICE},
                         /* deviceAdminPolicy= */ USES_POLICY_FORCE_LOCK,
                         caller.getPackageName(),
                         getAffectedUser(parent)
-                 ).getActiveAdmin();
+                );
+                if (Flags.activeAdminCleanup()) {
+                    adminComponent = enforcingAdmin.getComponentName();
+                } else {
+                    ActiveAdmin admin = enforcingAdmin.getActiveAdmin();
+                    adminComponent = admin == null ? null : admin.info.getComponent();
+                }
             } else {
-                admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
                         null,
-                        DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
+                        USES_POLICY_FORCE_LOCK,
                         parent,
                         LOCK_DEVICE);
+                adminComponent = admin == null ? null : admin.info.getComponent();
             }
             checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                adminComponent = admin == null ? null : admin.info.getComponent();
                 if (adminComponent != null) {
                     // For Profile Owners only, callers with only permission not allowed.
                     if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
@@ -7443,7 +7476,7 @@
      * privileged APIs.
      * <p>
      * This is done by checking that the calling package is authorized to perform the app operation
-     * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}.
+     * {@link AppOpsManager#OP_MANAGE_CREDENTIALS}.
      *
      * @param caller the calling identity
      * @return {@code true} if the calling process is the credential management app.
@@ -7453,7 +7486,7 @@
             AppOpsManager appOpsManager = mInjector.getAppOpsManager();
             if (appOpsManager == null) return false;
             return appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(),
-                    caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED;
+                    caller.getPackageName(), null, null) == MODE_ALLOWED;
         });
     }
 
@@ -7764,7 +7797,7 @@
     public void wipeDataWithReason(String callerPackageName, int flags,
             @NonNull String wipeReasonForUser, boolean calledOnParentInstance,
             boolean factoryReset) {
-        if (!mHasFeature && !hasCallingOrSelfPermission(permission.MASTER_CLEAR)) {
+        if (!mHasFeature && !hasCallingOrSelfPermission(MASTER_CLEAR)) {
             return;
         }
         CallerIdentity caller = getCallerIdentity(callerPackageName);
@@ -7777,7 +7810,6 @@
                 USES_POLICY_WIPE_DATA,
                 caller.getPackageName(),
                 factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
-        ActiveAdmin admin = enforcingAdmin.getActiveAdmin();
 
         checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA);
 
@@ -7786,10 +7818,20 @@
                     calledByProfileOwnerOnOrgOwnedDevice, calledOnParentInstance);
         }
 
-        int userId = admin != null ? admin.getUserHandle().getIdentifier()
-                : caller.getUserId();
-        Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
-                userId);
+        int userId;
+        ActiveAdmin admin = null;
+        if (Flags.activeAdminCleanup()) {
+            userId = enforcingAdmin.getUserId();
+            Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser,
+                    enforcingAdmin, userId);
+        } else {
+            admin = enforcingAdmin.getActiveAdmin();
+            userId = admin != null ? admin.getUserHandle().getIdentifier()
+                    : caller.getUserId();
+            Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin,
+                    userId);
+        }
+
         if (calledByProfileOwnerOnOrgOwnedDevice) {
             // When wipeData is called on the parent instance, it implies wiping the entire device.
             if (calledOnParentInstance) {
@@ -7810,25 +7852,36 @@
 
         final String adminName;
         final ComponentName adminComp;
-        if (admin != null) {
-            if (admin.isPermissionBased) {
-                adminComp = null;
-                adminName = caller.getPackageName();
-                event.setAdmin(adminName);
-            } else {
-                adminComp = admin.info.getComponent();
-                adminName = adminComp.flattenToShortString();
-                event.setAdmin(adminComp);
-            }
+        if (Flags.activeAdminCleanup()) {
+            adminComp = enforcingAdmin.getComponentName();
+            adminName = adminComp != null
+                    ? adminComp.flattenToShortString()
+                    : enforcingAdmin.getPackageName();
+            event.setAdmin(enforcingAdmin.getPackageName());
+            // Not including any HSUM handling here because the "else" branch in the "flag off"
+            // case below is unreachable under normal circumstances and for permission-based
+            // callers admin won't be null.
         } else {
-            adminComp = null;
-            adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
-            Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
-            event.setAdmin(adminName);
-            if (mInjector.userManagerIsHeadlessSystemUserMode()) {
-                // On headless system user mode, the call is meant to factory reset the whole
-                // device, otherwise the caller could simply remove the current user.
-                userId = UserHandle.USER_SYSTEM;
+            if (admin != null) {
+                if (admin.isPermissionBased) {
+                    adminComp = null;
+                    adminName = caller.getPackageName();
+                    event.setAdmin(adminName);
+                } else {
+                    adminComp = admin.info.getComponent();
+                    adminName = adminComp.flattenToShortString();
+                    event.setAdmin(adminComp);
+                }
+            } else {
+                adminComp = null;
+                adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
+                Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
+                event.setAdmin(adminName);
+                if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+                    // On headless system user mode, the call is meant to factory reset the whole
+                    // device, otherwise the caller could simply remove the current user.
+                    userId = UserHandle.USER_SYSTEM;
+                }
             }
         }
         event.write();
@@ -8142,7 +8195,7 @@
         synchronized (getLockObject()) {
             if (who == null) {
                 Preconditions.checkCallAuthorization(frpManagementAgentUid == caller.getUid()
-                                || hasCallingPermission(permission.MASTER_CLEAR)
+                                || hasCallingPermission(MASTER_CLEAR)
                                 || hasCallingPermission(MANAGE_DEVICE_POLICY_FACTORY_RESET),
                         "Must be called by the FRP management agent on device");
                 admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked();
@@ -8316,7 +8369,8 @@
         List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
         for (int i = 0; i < admins.size(); i++) {
             ActiveAdmin admin = admins.get(i);
-            if (admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+            if ((!Flags.activeAdminCleanup() && admin.isPermissionBased)
+                    || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
                 affectedUserIds.add(admin.getUserHandle().getIdentifier());
                 long timeout = admin.passwordExpirationTimeout;
                 admin.passwordExpirationDate =
@@ -8410,7 +8464,7 @@
      */
     private int getUserIdToWipeForFailedPasswords(ActiveAdmin admin) {
         final int userId = admin.getUserHandle().getIdentifier();
-        if (admin.isPermissionBased) {
+        if (!Flags.activeAdminCleanup() && admin.isPermissionBased) {
             return userId;
         }
         final ComponentName component = admin.info.getComponent();
@@ -8628,9 +8682,9 @@
             Slogf.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
         }
-        mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
-        mInjector.settingsGlobalPutInt(Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
-        mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+        mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
+        mInjector.settingsGlobalPutInt(Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
+        mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                 exclusionList);
     }
 
@@ -8751,7 +8805,7 @@
         }
 
         final int rawStatus = getEncryptionStatus();
-        if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
+        if ((rawStatus == ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) {
             return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
         }
         return rawStatus;
@@ -8775,7 +8829,7 @@
      */
     private int getEncryptionStatus() {
         if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
-            return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+            return ENCRYPTION_STATUS_ACTIVE_PER_USER;
         } else {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
@@ -8970,7 +9024,7 @@
         // Turn AUTO_TIME on in settings if it is required
         if (required) {
             mInjector.binderWithCleanCallingIdentity(
-                    () -> mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME,
+                    () -> mInjector.settingsGlobalPutInt(Global.AUTO_TIME,
                             1 /* AUTO_TIME on */));
         }
         DevicePolicyEventLogger
@@ -9004,26 +9058,13 @@
         if (!mHasFeature) {
             return;
         }
-
-        CallerIdentity caller;
-        if (Flags.setAutoTimeEnabledCoexistence()) {
-            caller = getCallerIdentity(who, callerPackageName);
-        } else {
-            caller = getCallerIdentity(who);
-        }
-
-        if (Flags.setAutoTimeEnabledCoexistence()) {
-            // The effect of this policy is device-wide.
-            enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
-        } else {
-            Objects.requireNonNull(who, "ComponentName is null");
-            Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
-                    || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
-                    caller));
-        }
+        CallerIdentity caller = getCallerIdentity(who);
+        Objects.requireNonNull(who, "ComponentName is null");
+        Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+                || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
+                caller));
         mInjector.binderWithCleanCallingIdentity(() ->
                 mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, enabled ? 1 : 0));
-
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_AUTO_TIME)
                 .setAdmin(caller.getPackageName())
@@ -9039,26 +9080,77 @@
         if (!mHasFeature) {
             return false;
         }
-        CallerIdentity caller;
-        if (Flags.setAutoTimeEnabledCoexistence()) {
-            caller = getCallerIdentity(who, callerPackageName);
-        } else {
-            caller = getCallerIdentity(who);
-        }
+        CallerIdentity caller = getCallerIdentity(who);
 
-        if (Flags.setAutoTimeEnabledCoexistence()) {
-            enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
-        } else {
-            Objects.requireNonNull(who, "ComponentName is null");
-            Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
-                    || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
-                    caller));
-        }
+        Objects.requireNonNull(who, "ComponentName is null");
+        Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+                || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller));
 
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
     }
 
     /**
+     * Set whether auto time is enabled on the device.
+     */
+    @Override
+    public void setAutoTimePolicy(String callerPackageName, int policy) {
+        if (!mHasFeature) {
+            return;
+        }
+
+        final Set<Integer> allowedValues =
+                Set.of(
+                        DevicePolicyManager.AUTO_TIME_ENABLED,
+                        DevicePolicyManager.AUTO_TIME_DISABLED,
+                        DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY);
+        Preconditions.checkArgument(
+                allowedValues.contains(policy), "Provided mode is not one of the allowed values.");
+
+        CallerIdentity caller = getCallerIdentity(callerPackageName);
+        // The effect of this policy is device-wide.
+        EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+                /* who */ null,
+                SET_TIME,
+                caller.getPackageName(),
+                UserHandle.USER_ALL
+        );
+        if (policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) {
+            mDevicePolicyEngine.removeGlobalPolicy(PolicyDefinition.AUTO_TIME, enforcingAdmin);
+        } else {
+            mDevicePolicyEngine.setGlobalPolicy(
+                    PolicyDefinition.AUTO_TIME,
+                    enforcingAdmin,
+                    new IntegerPolicyValue(policy));
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.SET_AUTO_TIME)
+                    .setAdmin(caller.getPackageName())
+                    .setBoolean(policy == DevicePolicyManager.AUTO_TIME_ENABLED)
+                    .write();
+        }
+    }
+
+    /**
+     * Returns whether auto time is used on the device or not.
+     */
+    @Override
+    public int getAutoTimePolicy(String callerPackageName) {
+        if (!mHasFeature) {
+            return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
+        }
+        CallerIdentity caller = getCallerIdentity(callerPackageName);
+        // The effect of this policy is device-wide.
+        EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+                /* who */ null,
+                SET_TIME,
+                caller.getPackageName(),
+                UserHandle.USER_ALL
+        );
+        Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin(
+                PolicyDefinition.AUTO_TIME, enforcingAdmin);
+        return state != null ? state : DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY;
+    }
+
+    /**
      * Set whether auto time zone is enabled on the device.
      */
     @Override
@@ -10364,7 +10456,7 @@
         policy.mDelegationMap.clear();
         policy.mStatusBarDisabled = false;
         policy.mSecondaryLockscreenEnabled = false;
-        policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
+        policy.mUserProvisioningState = STATE_USER_UNMANAGED;
         policy.mAffiliationIds.clear();
         resetAffiliationCacheLocked();
         policy.mLockTaskPackages.clear();
@@ -10399,7 +10491,7 @@
     @Override
     public int getUserProvisioningState(int userHandle) {
         if (!mHasFeature) {
-            return DevicePolicyManager.STATE_USER_UNMANAGED;
+            return STATE_USER_UNMANAGED;
         }
         final CallerIdentity caller = getCallerIdentity();
         Preconditions.checkCallAuthorization(canManageUsers(caller)
@@ -10454,7 +10546,7 @@
                     // ADB shell can only move directly from un-managed to finalized as part of
                     // directly setting profile-owner or device-owner.
                     if (getUserProvisioningState(userId)
-                            != DevicePolicyManager.STATE_USER_UNMANAGED
+                            != STATE_USER_UNMANAGED
                             || newState != STATE_USER_SETUP_FINALIZED) {
                         throw new IllegalStateException("Not allowed to change provisioning state "
                                 + "unless current provisioning state is unmanaged, and new state"
@@ -10492,9 +10584,9 @@
         }
         // Valid transitions for normal use-cases.
         switch (currentState) {
-            case DevicePolicyManager.STATE_USER_UNMANAGED:
+            case STATE_USER_UNMANAGED:
                 // Can move to any state from unmanaged (except itself as an edge case)..
-                if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) {
+                if (newState != STATE_USER_UNMANAGED) {
                     return;
                 }
                 break;
@@ -10518,7 +10610,7 @@
                 break;
             case DevicePolicyManager.STATE_USER_PROFILE_FINALIZED:
                 // Should only move to an unmanaged state after removing the work profile.
-                if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) {
+                if (newState == STATE_USER_UNMANAGED) {
                     return;
                 }
                 break;
@@ -10890,7 +10982,7 @@
                 UserHandle userHandle = UserHandle.of(userId);
                 userContext = mContext.createPackageContextAsUser(packageName, /* flags= */ 0,
                         userHandle);
-            } catch (PackageManager.NameNotFoundException nnfe) {
+            } catch (NameNotFoundException nnfe) {
                 Slogf.w(LOG_TAG, nnfe, "%s is not installed for user %d", packageName, userId);
                 return null;
             }
@@ -11110,20 +11202,20 @@
     }
 
     private boolean canQueryAdminPolicy(CallerIdentity caller) {
-        return hasCallingOrSelfPermission(permission.QUERY_ADMIN_POLICY);
+        return hasCallingOrSelfPermission(QUERY_ADMIN_POLICY);
     }
 
     private boolean hasPermission(String permission, int pid, int uid) {
-        return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
+        return mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED;
     }
 
     private boolean hasCallingPermission(String permission) {
-        return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
+        return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED;
     }
 
     private boolean hasCallingOrSelfPermission(String permission) {
         return mContext.checkCallingOrSelfPermission(permission)
-                == PackageManager.PERMISSION_GRANTED;
+                == PERMISSION_GRANTED;
     }
 
     private boolean hasPermissionForPreflight(CallerIdentity caller, String permission) {
@@ -11429,7 +11521,7 @@
 
     private String getEncryptionStatusName(int encryptionStatus) {
         switch (encryptionStatus) {
-            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
+            case ENCRYPTION_STATUS_ACTIVE_PER_USER:
                 return "per-user";
             case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED:
                 return "unsupported";
@@ -12511,7 +12603,7 @@
 
             if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
+                        USER_SETUP_COMPLETE, 1, userHandle);
             }
 
             sendProvisioningCompletedBroadcast(
@@ -13324,10 +13416,13 @@
         Objects.requireNonNull(systemEntity);
 
         CallerIdentity caller = getCallerIdentity();
-        if (caller.getUid() != Process.SYSTEM_UID) {
+        if (!isSystemUid(caller)) {
             throw new SecurityException("Only system services can call setUserRestrictionForUser"
                     + " on a target user: " + targetUser);
         }
+        if (!UserRestrictionsUtils.isValidRestriction(key)) {
+            throw new IllegalArgumentException("Invalid restriction key: " + key);
+        }
         if (VERBOSE_LOG) {
             Slogf.v(LOG_TAG, "Creating SystemEnforcingAdmin %s for calling package %s",
                     systemEntity, caller.getPackageName());
@@ -13460,6 +13555,31 @@
         logUserRestrictionCall(key, /* enabled= */ true, /* parent= */ false, caller,
                 UserHandle.USER_ALL);
     }
+
+    @Override
+    public void setUserRestrictionGloballyFromSystem(@NonNull String systemEntity, String key,
+            boolean enabled) {
+        Objects.requireNonNull(systemEntity);
+
+        CallerIdentity caller = getCallerIdentity();
+        if (!isSystemUid(caller)) {
+            throw new SecurityException("Only system services can call"
+                    + " setUserRestrictionGloballyFromSystem");
+        }
+        if (!UserRestrictionsUtils.isValidRestriction(key)) {
+            throw new IllegalArgumentException("Invalid restriction key: " + key);
+        }
+        if (VERBOSE_LOG) {
+            Slogf.v(LOG_TAG, "Creating SystemEnforcingAdmin %s for calling package %s",
+                    systemEntity, caller.getPackageName());
+        }
+        EnforcingAdmin admin = EnforcingAdmin.createSystemEnforcingAdmin(systemEntity);
+
+        setGlobalUserRestrictionInternal(admin, key, enabled);
+
+        logUserRestrictionCall(key, enabled, /* parent= */ false, caller, UserHandle.USER_ALL);
+    }
+
     private void setLocalUserRestrictionInternal(
             EnforcingAdmin admin, String key, boolean enabled, int userId) {
         PolicyDefinition<Boolean> policyDefinition =
@@ -13477,6 +13597,7 @@
                     userId);
         }
     }
+
     private void setGlobalUserRestrictionInternal(
             EnforcingAdmin admin, String key, boolean enabled) {
         PolicyDefinition<Boolean> policyDefinition =
@@ -13898,8 +14019,8 @@
             List<ResolveInfo> activitiesToEnable = mIPackageManager
                     .queryIntentActivities(intent,
                             intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                            PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                            MATCH_DIRECT_BOOT_AWARE
+                                    | MATCH_DIRECT_BOOT_UNAWARE,
                             parentUserId)
                     .getList();
 
@@ -14518,34 +14639,76 @@
         }
     }
 
+    private boolean hasActiveSupervisionTestAdminLocked(@UserIdInt int userId) {
+        ensureLocked();
+        if (mConstants.USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT) {
+            final DevicePolicyData policy = getUserData(userId);
+            for (ActiveAdmin admin : policy.mAdminMap.values()) {
+                if (admin != null && admin.testOnlyAdmin) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled,
             PersistableBundle options) {
-        Objects.requireNonNull(who, "ComponentName is null");
-
-        // Check can set secondary lockscreen enabled
-        final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(
-                isDefaultDeviceOwner(caller) || isProfileOwner(caller));
-        Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
-                "User %d is not allowed to call setSecondaryLockscreenEnabled",
+        if (Flags.secondaryLockscreenApiEnabled()) {
+            final CallerIdentity caller = getCallerIdentity();
+            final boolean isRoleHolder = isCallerSystemSupervisionRoleHolder(caller);
+            synchronized (getLockObject()) {
+                // TODO(b/378102594): Remove access for test admins.
+                final boolean isTestAdmin = hasActiveSupervisionTestAdminLocked(caller.getUserId());
+                Preconditions.checkCallAuthorization(isRoleHolder || isTestAdmin,
+                        "Caller (%d) is not the SYSTEM_SUPERVISION role holder",
                         caller.getUserId());
+            }
 
-        synchronized (getLockObject()) {
-            // Allow testOnly admins to bypass supervision config requirement.
-            Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
-                    || isSupervisionComponentLocked(caller.getComponentName()), "Admin %s is not "
-                    + "the default supervision component", caller.getComponentName());
-            DevicePolicyData policy = getUserData(caller.getUserId());
-            policy.mSecondaryLockscreenEnabled = enabled;
-            saveSettingsLocked(caller.getUserId());
+            if (mSupervisionManagerInternal != null) {
+                mSupervisionManagerInternal.setSupervisionLockscreenEnabledForUser(
+                        caller.getUserId(), enabled, options);
+            } else {
+                synchronized (getLockObject()) {
+                    DevicePolicyData policy = getUserData(caller.getUserId());
+                    policy.mSecondaryLockscreenEnabled = enabled;
+                    saveSettingsLocked(caller.getUserId());
+                }
+            }
+        } else {
+            Objects.requireNonNull(who, "ComponentName is null");
+
+            // Check can set secondary lockscreen enabled
+            final CallerIdentity caller = getCallerIdentity(who);
+            Preconditions.checkCallAuthorization(
+                    isDefaultDeviceOwner(caller) || isProfileOwner(caller));
+            Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
+                    "User %d is not allowed to call setSecondaryLockscreenEnabled",
+                            caller.getUserId());
+
+            synchronized (getLockObject()) {
+                // Allow testOnly admins to bypass supervision config requirement.
+                Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
+                        || isSupervisionComponentLocked(caller.getComponentName()),
+                        "Admin %s is not the default supervision component",
+                        caller.getComponentName());
+                DevicePolicyData policy = getUserData(caller.getUserId());
+                policy.mSecondaryLockscreenEnabled = enabled;
+                saveSettingsLocked(caller.getUserId());
+            }
         }
     }
 
     @Override
     public boolean isSecondaryLockscreenEnabled(@NonNull UserHandle userHandle) {
-        synchronized (getLockObject()) {
-            return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled;
+        if (Flags.secondaryLockscreenApiEnabled() && mSupervisionManagerInternal != null) {
+            return mSupervisionManagerInternal.isSupervisionLockscreenEnabledForUser(
+                    userHandle.getIdentifier());
+        } else {
+            synchronized (getLockObject()) {
+                return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled;
+            }
         }
     }
 
@@ -14744,7 +14907,7 @@
         if (policy == null) {
             // We default on the power button menu, in order to be consistent with pre-P
             // behaviour.
-            return DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
+            return LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
         }
         return policy.getFlags();
     }
@@ -14873,7 +15036,7 @@
                         "Permission denial: device owners cannot update %1$s", setting));
             }
 
-            if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
+            if (Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
                 // ignore if it contradicts an existing policy
                 long timeMs = getMaximumTimeToLock(
                         who, mInjector.userHandleGetCallingUserId(), /* parent */ false);
@@ -15378,7 +15541,7 @@
         final int N = users.size();
         for (int i = 0; i < N; i++) {
             int userHandle = users.get(i).id;
-            if (mInjector.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
+            if (mInjector.settingsSecureGetIntForUser(USER_SETUP_COMPLETE, 0,
                     userHandle) != 0) {
                 DevicePolicyData policy = getUserData(userHandle);
                 if (!policy.mUserSetupComplete) {
@@ -15406,7 +15569,7 @@
 
     private class SetupContentObserver extends ContentObserver {
         private final Uri mUserSetupComplete = Settings.Secure.getUriFor(
-                Settings.Secure.USER_SETUP_COMPLETE);
+                USER_SETUP_COMPLETE);
         private final Uri mPaired = Settings.Secure.getUriFor(Settings.Secure.DEVICE_PAIRED);
         private final Uri mDefaultImeChanged = Settings.Secure.getUriFor(
                 Settings.Secure.DEFAULT_INPUT_METHOD);
@@ -15454,7 +15617,7 @@
 
     private class DevicePolicyConstantsObserver extends ContentObserver {
         final Uri mConstantsUri =
-                Settings.Global.getUriFor(Settings.Global.DEVICE_POLICY_CONSTANTS);
+                Global.getUriFor(Global.DEVICE_POLICY_CONSTANTS);
 
         DevicePolicyConstantsObserver(Handler handler) {
             super(handler);
@@ -15747,9 +15910,9 @@
                 final int uid = Objects.requireNonNull(
                         mInjector.getPackageManager().getApplicationInfoAsUser(
                                 Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid;
-                return PackageManager.PERMISSION_GRANTED
+                return PERMISSION_GRANTED
                         == ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
+                        permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
                         -1, /* exported= */ true);
             } catch (NameNotFoundException ex) {
                 Slogf.w(LOG_TAG, "Cannot find the package %s to check for permissions.",
@@ -15886,7 +16049,7 @@
 
         private @Mode int findInteractAcrossProfilesResetMode(String packageName) {
             return getDefaultCrossProfilePackages().contains(packageName)
-                    ? AppOpsManager.MODE_ALLOWED
+                    ? MODE_ALLOWED
                     : AppOpsManager.opToDefaultMode(AppOpsManager.OP_INTERACT_ACROSS_PROFILES);
         }
 
@@ -16205,7 +16368,8 @@
         if (admin.mPasswordPolicy.quality < minPasswordQuality) {
             return false;
         }
-        return admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+        return (!Flags.activeAdminCleanup() && admin.isPermissionBased)
+                || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
     }
 
     @Override
@@ -16611,13 +16775,13 @@
             synchronized (getLockObject()) {
                 long ident = mInjector.binderClearCallingIdentity();
                 boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
-                        >= android.os.Build.VERSION_CODES.Q;
+                        >= Build.VERSION_CODES.Q;
 
                 try {
                     if (!isPostQAdmin) {
                         // Legacy admins assume that they cannot control pre-M apps
                         if (getTargetSdk(packageName, caller.getUserId())
-                                < android.os.Build.VERSION_CODES.M) {
+                                < Build.VERSION_CODES.M) {
                             callback.sendResult(null);
                             return;
                         }
@@ -16628,7 +16792,7 @@
                     }
                     if (grantState == PERMISSION_GRANT_STATE_GRANTED
                             || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
-                            || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
+                            || grantState == PERMISSION_GRANT_STATE_DEFAULT) {
                         AdminPermissionControlParams permissionParams =
                                 new AdminPermissionControlParams(packageName, permission,
                                         grantState,
@@ -16663,26 +16827,26 @@
 
     private static final List<String> SENSOR_PERMISSIONS = new ArrayList<>();
     {
-        SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
-        SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
-        SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
-        SENSOR_PERMISSIONS.add(Manifest.permission.CAMERA);
-        SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
-        SENSOR_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION);
-        SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
-        SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA);
-        SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO);
-        SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+        SENSOR_PERMISSIONS.add(permission.ACCESS_FINE_LOCATION);
+        SENSOR_PERMISSIONS.add(permission.ACCESS_BACKGROUND_LOCATION);
+        SENSOR_PERMISSIONS.add(permission.ACCESS_COARSE_LOCATION);
+        SENSOR_PERMISSIONS.add(permission.CAMERA);
+        SENSOR_PERMISSIONS.add(permission.RECORD_AUDIO);
+        SENSOR_PERMISSIONS.add(permission.ACTIVITY_RECOGNITION);
+        SENSOR_PERMISSIONS.add(permission.BODY_SENSORS);
+        SENSOR_PERMISSIONS.add(permission.BACKGROUND_CAMERA);
+        SENSOR_PERMISSIONS.add(permission.RECORD_BACKGROUND_AUDIO);
+        SENSOR_PERMISSIONS.add(permission.BODY_SENSORS_BACKGROUND);
     }
 
     private boolean canGrantPermission(CallerIdentity caller, String permission,
             String targetPackageName) {
         boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
-                >= android.os.Build.VERSION_CODES.Q;
+                >= Build.VERSION_CODES.Q;
         if (!isPostQAdmin) {
             // Legacy admins assume that they cannot control pre-M apps
             if (getTargetSdk(targetPackageName, caller.getUserId())
-                    < android.os.Build.VERSION_CODES.M) {
+                    < Build.VERSION_CODES.M) {
                 return false;
             }
         }
@@ -16729,7 +16893,7 @@
             throws RemoteException {
         int granted;
         if (getTargetSdk(caller.getPackageName(), caller.getUserId())
-                < android.os.Build.VERSION_CODES.Q) {
+                < Build.VERSION_CODES.Q) {
             // The per-Q behavior was to not check the app-ops state.
             granted = mIPackageManager.checkPermission(permission, packageName, userId);
         } else {
@@ -16738,11 +16902,11 @@
                 if (packageState == null) {
                     Slog.w(LOG_TAG, "Can't get permission state for missing package "
                             + packageName);
-                    return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+                    return PERMISSION_GRANT_STATE_DEFAULT;
                 } else if (!packageState.getUserStateOrDefault(userId).isInstalled()) {
                     Slog.w(LOG_TAG, "Can't get permission state for uninstalled package "
                             + packageName);
-                    return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+                    return PERMISSION_GRANT_STATE_DEFAULT;
                 } else {
                     if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
                             PermissionChecker.PID_UNKNOWN,
@@ -16750,7 +16914,7 @@
                             != PermissionChecker.PERMISSION_GRANTED) {
                         granted = PackageManager.PERMISSION_DENIED;
                     } else {
-                        granted = PackageManager.PERMISSION_GRANTED;
+                        granted = PERMISSION_GRANTED;
                     }
 
                 }
@@ -16761,11 +16925,11 @@
         if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
                 != PackageManager.FLAG_PERMISSION_POLICY_FIXED) {
             // Not controlled by policy
-            return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+            return PERMISSION_GRANT_STATE_DEFAULT;
         } else {
             // Policy controlled so return result based on permission grant state
-            return granted == PackageManager.PERMISSION_GRANTED
-                    ? DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
+            return granted == PERMISSION_GRANTED
+                    ? PERMISSION_GRANT_STATE_GRANTED
                     : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
         }
     }
@@ -16885,9 +17049,9 @@
         }
         if (action != null) {
             switch (action) {
-                case DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE:
+                case ACTION_PROVISION_MANAGED_PROFILE:
                     return checkManagedProfileProvisioningPreCondition(packageName, userId);
-                case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
+                case ACTION_PROVISION_MANAGED_DEVICE:
                 case DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE:
                     return checkDeviceOwnerProvisioningPreCondition(componentName, userId);
             }
@@ -18234,7 +18398,7 @@
                 hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
         boolean isUserCompleted = mInjector.settingsSecureGetIntForUser(
-                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0;
+                USER_SETUP_COMPLETE, 0, userId) != 0;
         DevicePolicyData policy = getUserData(userId);
         policy.mUserSetupComplete = isUserCompleted;
         mStateCache.setDeviceProvisioned(isUserCompleted);
@@ -19081,6 +19245,14 @@
         }
     }
 
+    private boolean isAnyResetPasswordTokenActiveForUser(int userId) {
+        return mDevicePolicyEngine
+                .getLocalPoliciesSetByAdmins(PolicyDefinition.RESET_PASSWORD_TOKEN, userId)
+                .values()
+                .stream()
+                .anyMatch((p) -> isResetPasswordTokenActiveForUserLocked(p.getValue(), userId));
+    }
+
     private boolean isResetPasswordTokenActiveForUserLocked(
             long passwordTokenHandle, int userHandle) {
         if (passwordTokenHandle != 0) {
@@ -19857,7 +20029,7 @@
     }
 
     private boolean isDeviceAB() {
-        return "true".equalsIgnoreCase(android.os.SystemProperties
+        return "true".equalsIgnoreCase(SystemProperties
                 .get(AB_DEVICE_KEY, ""));
     }
 
@@ -20124,7 +20296,7 @@
         return mOwners.hasDeviceOwner()
                 && mInjector.getIActivityManager().getLockTaskModeState()
                         == ActivityManager.LOCK_TASK_MODE_LOCKED
-                && !isLockTaskFeatureEnabled(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO)
+                && !isLockTaskFeatureEnabled(LOCK_TASK_FEATURE_SYSTEM_INFO)
                 && !deviceHasKeyguard()
                 && !inEphemeralUserSession();
     }
@@ -20135,7 +20307,7 @@
         int lockTaskFeatures = policy == null
                 // We default on the power button menu, in order to be consistent with pre-P
                 // behaviour.
-                ? DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS
+                ? LOCK_TASK_FEATURE_GLOBAL_ACTIONS
                 : policy.getFlags();
         return (lockTaskFeatures & lockTaskFeature) == lockTaskFeature;
     }
@@ -20881,7 +21053,7 @@
 
     private boolean canHandleCheckPolicyComplianceIntent(CallerIdentity caller) {
         mInjector.binderWithCleanCallingIdentity(() -> {
-            final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE);
+            final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
             intent.setPackage(caller.getPackageName());
             final List<ResolveInfo> handlers =
                     mInjector.getPackageManager().queryIntentActivitiesAsUser(intent, /* flags= */
@@ -20936,6 +21108,9 @@
         Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()),
                 String.format(NOT_SYSTEM_CALLER_MSG,
                         "call canProfileOwnerResetPasswordWhenLocked"));
+        if (Flags.resetPasswordWithTokenCoexistence()) {
+            return isAnyResetPasswordTokenActiveForUser(userId);
+        }
         synchronized (getLockObject()) {
             final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(userId);
             DevicePolicyData policy = getUserData(userId);
@@ -21087,6 +21262,17 @@
         Preconditions.checkCallAuthorization(
                 hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
 
+        if (Flags.splitCreateManagedProfileEnabled()) {
+            return mInjector.binderWithCleanCallingIdentity(() -> {
+                UserHandle managedProfileUser =
+                        createManagedProfileInternal(provisioningParams, caller);
+                maybeMigrateAccount(managedProfileUser.getIdentifier(), caller.getUserId(),
+                        provisioningParams.getAccountToMigrate(),
+                        provisioningParams.isKeepingAccountOnMigration(), callerPackage);
+                finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser);
+                return managedProfileUser;
+            });
+        }
         provisioningParams.logParams(callerPackage);
 
         UserInfo userInfo = null;
@@ -21180,6 +21366,130 @@
     }
 
     @Override
+    public UserHandle createManagedProfile(
+            @NonNull ManagedProfileProvisioningParams provisioningParams,
+            @NonNull String callerPackage) {
+        Objects.requireNonNull(provisioningParams, "provisioningParams is null");
+        Objects.requireNonNull(callerPackage, "callerPackage is null");
+        Objects.requireNonNull(provisioningParams.getProfileAdminComponentName(), "admin is null");
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+        CallerIdentity caller = getCallerIdentity(callerPackage);
+
+        return mInjector.binderWithCleanCallingIdentity(() ->
+                createManagedProfileInternal(provisioningParams, caller));
+    }
+
+    private UserHandle createManagedProfileInternal(
+            @NonNull ManagedProfileProvisioningParams provisioningParams,
+            @NonNull CallerIdentity caller) {
+        provisioningParams.logParams(caller.getPackageName());
+        final ComponentName admin = provisioningParams.getProfileAdminComponentName();
+        final int callingUserId = caller.getUserId();
+        UserInfo userInfo = null;
+        try {
+            final int result = checkProvisioningPreconditionSkipPermission(
+                    ACTION_PROVISION_MANAGED_PROFILE, admin, callingUserId);
+            if (result != STATUS_OK) {
+                throw new ServiceSpecificException(
+                        ERROR_PRE_CONDITION_FAILED,
+                        "Provisioning preconditions failed with result: " + result);
+            }
+
+            final long startTime = SystemClock.elapsedRealtime();
+
+            onCreateAndProvisionManagedProfileStarted(provisioningParams);
+
+            userInfo = createProfileForUser(provisioningParams, callingUserId);
+            if (userInfo == null) {
+                throw new ServiceSpecificException(
+                        ERROR_PROFILE_CREATION_FAILED,
+                        "Error creating profile, createProfileForUserEvenWhenDisallowed "
+                                + "returned null.");
+            }
+            resetInteractAcrossProfilesAppOps(caller.getUserId());
+            logEventDuration(
+                    DevicePolicyEnums.PLATFORM_PROVISIONING_CREATE_PROFILE_MS,
+                    startTime,
+                    caller.getPackageName());
+
+            maybeInstallDevicePolicyManagementRoleHolderInUser(userInfo.id);
+            installExistingAdminPackage(userInfo.id, admin.getPackageName());
+
+            if (!enableAdminAndSetProfileOwner(userInfo.id, caller.getUserId(), admin)) {
+                throw new ServiceSpecificException(
+                        ERROR_SETTING_PROFILE_OWNER_FAILED,
+                        "Error setting profile owner.");
+            }
+            setUserSetupComplete(userInfo.id);
+            startProfileForSetup(userInfo.id, caller.getPackageName());
+
+            if (provisioningParams.isOrganizationOwnedProvisioning()) {
+                synchronized (getLockObject()) {
+                    setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+                            true);
+                }
+            }
+            return userInfo.getUserHandle();
+        } catch (Exception e) {
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.PLATFORM_PROVISIONING_ERROR)
+                    .setStrings(caller.getPackageName())
+                    .write();
+            // In case of any errors during provisioning, remove the newly created profile.
+            if (userInfo != null) {
+                mUserManager.removeUserEvenWhenDisallowed(userInfo.id);
+            }
+            throw e;
+        }
+    }
+
+    private UserInfo createProfileForUser(ManagedProfileProvisioningParams params, int userId) {
+        final Set<String> nonRequiredApps = params.isLeaveAllSystemAppsEnabled()
+                ? Collections.emptySet()
+                : mOverlayPackagesProvider.getNonRequiredApps(params.getProfileAdminComponentName(),
+                        userId, ACTION_PROVISION_MANAGED_PROFILE);
+        if (nonRequiredApps.isEmpty()) {
+            Slogf.i(LOG_TAG, "No disallowed packages for the managed profile.");
+        } else {
+            for (String packageName : nonRequiredApps) {
+                Slogf.i(LOG_TAG, "Disallowed package [" + packageName + "]");
+            }
+        }
+        return mUserManager.createProfileForUserEvenWhenDisallowed(
+                params.getProfileName(),
+                UserManager.USER_TYPE_PROFILE_MANAGED,
+                UserInfo.FLAG_DISABLED,
+                userId,
+                nonRequiredApps.toArray(new String[nonRequiredApps.size()]));
+    }
+
+    @Override
+    public void finalizeCreateManagedProfile(
+            @NonNull ManagedProfileProvisioningParams provisioningParams,
+            @NonNull UserHandle managedProfileUser) {
+        Objects.requireNonNull(provisioningParams, "provisioningParams is null");
+        Objects.requireNonNull(managedProfileUser, "managedProfileUser is null");
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        mInjector.binderWithCleanCallingIdentity(() -> {
+            finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser);
+        });
+    }
+
+    private void finalizeCreateManagedProfileInternal(
+            @NonNull ManagedProfileProvisioningParams provisioningParams,
+            @NonNull UserHandle managedProfileUser
+    ) {
+        onCreateAndProvisionManagedProfileCompleted(provisioningParams);
+        sendProvisioningCompletedBroadcast(
+                managedProfileUser.getIdentifier(),
+                ACTION_PROVISION_MANAGED_PROFILE,
+                provisioningParams.isLeaveAllSystemAppsEnabled());
+    }
+
+    @Override
     public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
             Account migratedAccount) {
         Preconditions.checkCallAuthorization(
@@ -21349,7 +21659,7 @@
 
     private void pregrantDefaultInteractAcrossProfilesAppOps(@UserIdInt int userId) {
         final String op =
-                AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
+                AppOpsManager.permissionToOp(permission.INTERACT_ACROSS_PROFILES);
         for (String packageName : getConfigurableDefaultCrossProfilePackages(userId)) {
             if (!appOpIsDefaultOrAllowed(userId, op, packageName)) {
                 continue;
@@ -21552,7 +21862,8 @@
                 Slogf.i(LOG_TAG, "Account removed from the primary user.");
             } else {
                 // TODO(174768447): Revisit start activity logic.
-                final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class);
+                final Intent removeIntent =
+                        result.getParcelable(AccountManager.KEY_INTENT, Intent.class);
                 removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
                 if (removeIntent != null) {
                     Slogf.i(LOG_TAG, "Starting activity to remove account");
@@ -21848,7 +22159,7 @@
         }
         synchronized (getLockObject()) {
             mInjector.settingsGlobalPutStringForUser(
-                    Settings.Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
+                    Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId);
         }
 
         setUserProvisioningState(STATE_USER_SETUP_FINALIZED, userId);
@@ -22111,7 +22422,7 @@
     @Override
     public boolean isDevicePotentiallyStolen(String callerPackageName) {
         final CallerIdentity caller = getCallerIdentity(callerPackageName);
-        if (!android.app.admin.flags.Flags.deviceTheftImplEnabled()) {
+        if (!Flags.deviceTheftImplEnabled()) {
             return false;
         }
         enforcePermission(QUERY_DEVICE_STOLEN_STATE, caller.getPackageName(),
@@ -22147,7 +22458,7 @@
     @Override
     public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+                permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
         Objects.requireNonNull(drawables, "drawables must be provided.");
 
@@ -22163,7 +22474,7 @@
     @Override
     public void resetDrawables(@NonNull List<String> drawableIds) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+                permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
         Objects.requireNonNull(drawableIds, "drawableIds must be provided.");
 
@@ -22189,7 +22500,7 @@
     @Override
     public void setStrings(@NonNull List<DevicePolicyStringResource> strings) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+                permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
         Objects.requireNonNull(strings, "strings must be provided.");
 
@@ -22204,7 +22515,7 @@
     @Override
     public void resetStrings(@NonNull List<String> stringIds) {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+                permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
 
         mInjector.binderWithCleanCallingIdentity(() -> {
             if (mDeviceManagementResourcesProvider.removeStrings(stringIds)) {
@@ -22274,7 +22585,7 @@
     @Override
     public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+                permission.MANAGE_ROLE_HOLDERS));
         setBypassDevicePolicyManagementRoleQualificationStateInternal(
                 /* currentRoleHolder= */ null, /* allowBypass= */ false);
     }
@@ -22282,7 +22593,7 @@
     @Override
     public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
         Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+                permission.MANAGE_ROLE_HOLDERS));
         return mInjector.binderWithCleanCallingIdentity(() -> {
             if (getUserData(
                     UserHandle.USER_SYSTEM).mBypassDevicePolicyManagementRoleQualifications) {
@@ -23278,7 +23589,8 @@
             return EnforcingAdmin.createDeviceAdminEnforcingAdmin(admin.info.getComponent(), userId,
                     admin);
         }
-        admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+        admin = Flags.activeAdminCleanup()
+                ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId);
         return  EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
     }
 
@@ -23301,8 +23613,8 @@
                 }
             }
         }
-
-        admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+        admin = Flags.activeAdminCleanup()
+                ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId);
         return  EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin);
     }
 
@@ -23874,7 +24186,7 @@
                     if (!isRuntimePermission(permission)) {
                         continue;
                     }
-                    int grantState = DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+                    int grantState = PERMISSION_GRANT_STATE_DEFAULT;
                     try {
                         grantState = getPermissionGrantStateForUser(
                                 packageInfo.packageName, permission,
@@ -23887,7 +24199,7 @@
                         Slogf.e(LOG_TAG, e, "Error retrieving permission grant state for %s "
                                         + "and %s", packageInfo.packageName, permission);
                     }
-                    if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
+                    if (grantState == PERMISSION_GRANT_STATE_DEFAULT) {
                         // Not Controlled by a policy
                         continue;
                     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 634f1bc..1fd628a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -23,6 +23,7 @@
 import android.app.admin.DpcAuthority;
 import android.app.admin.RoleAuthority;
 import android.app.admin.UnknownAuthority;
+import android.app.admin.flags.Flags;
 import android.content.ComponentName;
 import android.os.UserHandle;
 
@@ -280,6 +281,10 @@
         return getAuthorities().contains(authority);
     }
 
+    boolean isSystemAuthority() {
+        return mIsSystemAuthority;
+    }
+
     @NonNull
     String getPackageName() {
         return mPackageName;
@@ -291,9 +296,17 @@
 
     @Nullable
     public ActiveAdmin getActiveAdmin() {
+        if (Flags.activeAdminCleanup()) {
+            throw new UnsupportedOperationException("getActiveAdmin() no longer supported");
+        }
         return mActiveAdmin;
     }
 
+    @Nullable
+    ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     @NonNull
     android.app.admin.EnforcingAdmin getParcelableAdmin() {
         Authority authority;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index a5aeaac..24b16b7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -349,6 +349,16 @@
                     PolicyEnforcerCallbacks::setMtePolicy,
                     new IntegerPolicySerializer());
 
+    static PolicyDefinition<Integer> AUTO_TIME = new PolicyDefinition<>(
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIME_POLICY),
+            new TopPriority<>(List.of(
+                    EnforcingAdmin.getRoleAuthorityOf(SYSTEM_SUPERVISION_ROLE),
+                    EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
+                    EnforcingAdmin.DPC_AUTHORITY)),
+            POLICY_FLAG_GLOBAL_ONLY_POLICY,
+            PolicyEnforcerCallbacks::setAutoTimePolicy,
+            new IntegerPolicySerializer());
+
     private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
     private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
 
@@ -397,6 +407,7 @@
                 PACKAGES_SUSPENDED);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY,
                 MEMORY_TAGGING);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIME_POLICY, AUTO_TIME);
 
         // User Restriction Policies
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 40d8dae..8f80004 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -212,6 +212,25 @@
         return AndroidFuture.completedFuture(true);
     }
 
+    public static CompletableFuture<Boolean> setAutoTimePolicy(
+            Integer policy, Context context, Integer userId, PolicyKey policyKey) {
+        if (!Flags.setAutoTimeEnabledCoexistence()) {
+            Slogf.w(LOG_TAG, "Trying to enforce setAutoTimePolicy while flag is off.");
+            return AndroidFuture.completedFuture(true);
+        }
+        return Binder.withCleanCallingIdentity(() -> {
+            Objects.requireNonNull(context);
+            if (policy != null
+                    && policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) {
+                return AndroidFuture.completedFuture(false);
+            }
+            int enabled = policy != null && policy == DevicePolicyManager.AUTO_TIME_ENABLED ? 1 : 0;
+            return AndroidFuture.completedFuture(
+                    Settings.Global.putInt(
+                            context.getContentResolver(), Settings.Global.AUTO_TIME,  enabled));
+        });
+    }
+
     private static class BlockingCallback {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final AtomicReference<Boolean> mValue = new AtomicReference<>();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 19b0343..da478f3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -249,8 +249,9 @@
 import com.android.server.security.FileIntegrityService;
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
-import com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService;
 import com.android.server.security.advancedprotection.AdvancedProtectionService;
+import com.android.server.security.authenticationpolicy.AuthenticationPolicyService;
+import com.android.server.security.forensic.ForensicService;
 import com.android.server.security.rkp.RemoteProvisioningService;
 import com.android.server.selinux.SelinuxAuditLogsService;
 import com.android.server.sensorprivacy.SensorPrivacyService;
@@ -1760,6 +1761,13 @@
             mSystemServiceManager.startService(LogcatManagerService.class);
             t.traceEnd();
 
+            if (!isWatch && !isTv && !isAutomotive
+                    && android.security.Flags.aflApi()) {
+                t.traceBegin("StartForensicService");
+                mSystemServiceManager.startService(ForensicService.class);
+                t.traceEnd();
+            }
+
             if (AppFunctionManagerConfiguration.isSupported(context)) {
                 t.traceBegin("StartAppFunctionManager");
                 mSystemServiceManager.startService(AppFunctionManagerService.class);
@@ -2652,8 +2660,8 @@
             t.traceEnd();
 
             if (android.adaptiveauth.Flags.enableAdaptiveAuth()) {
-                t.traceBegin("StartAdaptiveAuthenticationService");
-                mSystemServiceManager.startService(AdaptiveAuthenticationService.class);
+                t.traceBegin("StartAuthenticationPolicyService");
+                mSystemServiceManager.startService(AuthenticationPolicyService.class);
                 t.traceEnd();
             }
 
@@ -2761,8 +2769,9 @@
             mSystemServiceManager.startService(WEAR_MODE_SERVICE_CLASS);
             t.traceEnd();
 
-            boolean enableWristOrientationService = SystemProperties.getBoolean(
-                    "config.enable_wristorientation", false);
+            boolean enableWristOrientationService =
+                    !android.server.Flags.migrateWristOrientation()
+                    && SystemProperties.getBoolean("config.enable_wristorientation", false);
             if (enableWristOrientationService) {
                 t.traceBegin("StartWristOrientationService");
                 mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS);
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index e2ac22d..4412968 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -39,6 +39,14 @@
 }
 
 flag {
+     name: "migrate_wrist_orientation"
+     namespace: "wear_frameworks"
+     description: "Migrate wrist orientation service functionality to wear settings service"
+     bug: "352725980"
+     is_fixed_read_only: true
+}
+
+flag {
     name: "allow_network_time_update_service"
     namespace: "wear_systems"
     description: "Allow NetworkTimeUpdateService on Wear"
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 4e86888..e307e52 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -144,6 +144,10 @@
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             UsbManager usbManager = getContext().getSystemService(UsbManager.class);
+            if (usbManager == null) {
+                mAdbActive = false;
+                return;
+            }
             mAdbActive = ((usbManager.getCurrentFunctions() & UsbManager.FUNCTION_ADB) == 1);
             Log.d(LOG_TAG, "ADB is " + mAdbActive + " on system startup");
         }
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java
index 67e2547..53a25dd 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionService.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java
@@ -21,10 +21,11 @@
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.supervision.ISupervisionManager;
+import android.app.supervision.SupervisionManagerInternal;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.UserInfo;
-import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -179,8 +180,15 @@
         }
 
         @Override
+        public boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId) {
+            synchronized (getLockObject()) {
+                return getUserDataLocked(userId).supervisionLockScreenEnabled;
+            }
+        }
+
+        @Override
         public void setSupervisionLockscreenEnabledForUser(
-                @UserIdInt int userId, boolean enabled, @Nullable Bundle options) {
+                @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options) {
             synchronized (getLockObject()) {
                 SupervisionUserData data = getUserDataLocked(userId);
                 data.supervisionLockScreenEnabled = enabled;
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
index 5616237..1dd48f5 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.util.IndentingPrintWriter;
 
 /** User specific data, used internally by the {@link SupervisionService}. */
@@ -27,7 +27,7 @@
     public final @UserIdInt int userId;
     public boolean supervisionEnabled;
     public boolean supervisionLockScreenEnabled;
-    @Nullable public Bundle supervisionLockScreenOptions;
+    @Nullable public PersistableBundle supervisionLockScreenOptions;
 
     public SupervisionUserData(@UserIdInt int userId) {
         this.userId = userId;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
index 1be5cef..acd34e3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -60,6 +61,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.List;
 
 @AppModeFull
 @AppModeNonSdkSandbox
@@ -124,7 +126,8 @@
     @Test
     public void changeNonExportedComponent_sendPackageChangedBroadcastToSystem_withPermission()
             throws Exception {
-        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
+        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+                new String[0] /* sharedPackages */);
 
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockActivityManagerInternal).broadcastIntentWithCallback(
@@ -140,7 +143,8 @@
     @Test
     public void changeNonExportedComponent_sendPackageChangedBroadcastToApplicationItself()
             throws Exception {
-        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */);
+        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+                new String[0] /* sharedPackages */);
 
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -150,9 +154,45 @@
         assertThat(intent.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
     }
 
+    @RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES)
+    @Test
+    public void changeNonExportedComponent_sendPackageChangedBroadcastToSharedUserIdApplications()
+            throws Exception {
+        changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */,
+                new String[]{"shared.package"} /* sharedPackages */);
+
+        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
+        ArgumentCaptor<String[]> captorRequiredPermissions = ArgumentCaptor.forClass(
+                String[].class);
+        verify(mMockActivityManagerInternal, times(3)).broadcastIntentWithCallback(
+                captorIntent.capture(), eq(null), captorRequiredPermissions.capture(), anyInt(),
+                eq(null), eq(null), eq(null));
+        List<Intent> intents = captorIntent.getAllValues();
+        List<String[]> requiredPermissions = captorRequiredPermissions.getAllValues();
+        assertNotNull(intents);
+        assertThat(intents.size()).isEqualTo(3);
+
+        final Intent intent1 = intents.get(0);
+        final String[] requiredPermission1 = requiredPermissions.get(0);
+        assertThat(intent1.getPackage()).isEqualTo("android");
+        assertThat(requiredPermission1).isEqualTo(
+                new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED});
+
+        final Intent intent2 = intents.get(1);
+        final String[] requiredPermission2 = requiredPermissions.get(1);
+        assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME);
+        assertThat(requiredPermission2).isNull();
+
+        final Intent intent3 = intents.get(2);
+        final String[] requiredPermission3 = requiredPermissions.get(2);
+        assertThat(intent3.getPackage()).isEqualTo("shared.package");
+        assertThat(requiredPermission3).isNull();
+    }
+
     @Test
     public void changeExportedComponent_sendPackageChangedBroadcastToAll() throws Exception {
-        changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */);
+        changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */,
+                new String[0] /* sharedPackages */);
 
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null),
@@ -162,11 +202,14 @@
         assertNull(intent.getPackage());
     }
 
-    private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent) {
+    private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent,
+            String[] sharedPackages) {
         when(mMockSnapshot.getPackageStateInternal(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
                 anyInt())).thenReturn(mMockPackageStateInternal);
         when(mMockSnapshot.isInstantAppInternal(any(), anyInt(), anyInt())).thenReturn(false);
         when(mMockSnapshot.getVisibilityAllowLists(any(), any())).thenReturn(null);
+        when(mMockSnapshot.getSharedUserPackagesForPackage(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME),
+                anyInt())).thenReturn(sharedPackages);
         when(mMockPackageStateInternal.getPkg()).thenReturn(mMockAndroidPackageInternal);
 
         when(mMockParsedActivity.getClassName()).thenReturn(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 69714f3..3fdb53f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -582,6 +582,34 @@
             PackageImpl::setSystemExt,
             true
         ),
+        getSetByValue(
+            AndroidPackage::getAlternateLauncherIconResIds,
+            PackageImpl::setAlternateLauncherIconResIds,
+            intArrayOf(3, 5, 7),
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    { it.size },
+                    { it[0] },
+                    { it[1] },
+                    { it[2] }
+                )
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getAlternateLauncherLabelResIds,
+            PackageImpl::setAlternateLauncherLabelResIds,
+            intArrayOf(3, 5, 7),
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    { it.size },
+                    { it[0] },
+                    { it[1] },
+                    { it[2] }
+                )
+            }
+        ),
     )
 
     override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
index 08155c7..9772ef9 100644
--- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java
@@ -2380,10 +2380,14 @@
     @Test
     public void doTestMigrateIkeSession_Vcn() throws Exception {
         final int expectedKeepalive = 2097; // Any unlikely number will do
-        final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder()
-                .addTransportType(TRANSPORT_CELLULAR)
-                .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive))
-                .build();
+        final NetworkCapabilities vcnNc =
+                new NetworkCapabilities.Builder()
+                        .addTransportType(TRANSPORT_CELLULAR)
+                        .setTransportInfo(
+                                new VcnTransportInfo.Builder()
+                                        .setMinUdpPort4500NatTimeoutSeconds(expectedKeepalive)
+                                        .build())
+                        .build();
         final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile(
                 true /* isAutomaticIpVersionSelectionEnabled */,
                 true /* isAutomaticNattKeepaliveTimerEnabled */,
diff --git a/services/tests/apexsystemservices/services/Android.bp b/services/tests/apexsystemservices/services/Android.bp
index 477ea4c..70d84dc 100644
--- a/services/tests/apexsystemservices/services/Android.bp
+++ b/services/tests/apexsystemservices/services/Android.bp
@@ -17,4 +17,5 @@
     ],
     visibility: ["//frameworks/base/services/tests/apexsystemservices:__subpackages__"],
     apex_available: ["//apex_available:anyapex"],
+    compile_dex: true,
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 80e5ee3..759976f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -226,6 +226,9 @@
             "EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED";
     private static final String EVENT_DISPLAY_CONNECTED = "EVENT_DISPLAY_CONNECTED";
     private static final String EVENT_DISPLAY_DISCONNECTED = "EVENT_DISPLAY_DISCONNECTED";
+    private static final String EVENT_DISPLAY_REFRESH_RATE_CHANGED =
+            "EVENT_DISPLAY_REFRESH_RATE_CHANGED";
+    private static final String EVENT_DISPLAY_STATE_CHANGED = "EVENT_DISPLAY_STATE_CHANGED";
     private static final String DISPLAY_GROUP_EVENT_ADDED = "DISPLAY_GROUP_EVENT_ADDED";
     private static final String DISPLAY_GROUP_EVENT_REMOVED = "DISPLAY_GROUP_EVENT_REMOVED";
     private static final String DISPLAY_GROUP_EVENT_CHANGED = "DISPLAY_GROUP_EVENT_CHANGED";
@@ -4234,6 +4237,10 @@
                     return EVENT_DISPLAY_CONNECTED;
                 case DisplayManagerGlobal.EVENT_DISPLAY_DISCONNECTED:
                     return EVENT_DISPLAY_DISCONNECTED;
+                case DisplayManagerGlobal.EVENT_DISPLAY_REFRESH_RATE_CHANGED:
+                    return EVENT_DISPLAY_REFRESH_RATE_CHANGED;
+                case DisplayManagerGlobal.EVENT_DISPLAY_STATE_CHANGED:
+                    return EVENT_DISPLAY_STATE_CHANGED;
                 default:
                     return "UNKNOWN: " + eventType;
             }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index b6da3ae..ff652a2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -35,7 +35,9 @@
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CONNECTED;
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_DISCONNECTED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED;
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_STATE_CHANGED;
 import static com.android.server.display.layout.Layout.Display.POSITION_REAR;
 import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN;
 import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SELECTIVE_STAY_AWAKE;
@@ -1158,6 +1160,29 @@
                 mLogicalDisplayMapper.getDisplayLocked(device2).getDevicePositionLocked());
     }
 
+    @Test
+    public void updateAndGetMaskForDisplayPropertyChanges_getsPropertyChangedFlags() {
+        // Change the display state
+        DisplayInfo newDisplayInfo = new DisplayInfo();
+        newDisplayInfo.state = STATE_OFF;
+        assertEquals(LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
+                mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+
+        // Change the refresh rate override
+        newDisplayInfo = new DisplayInfo();
+        newDisplayInfo.refreshRateOverride = 30;
+        assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED,
+                mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+
+        // Change multiple properties
+        newDisplayInfo = new DisplayInfo();
+        newDisplayInfo.refreshRateOverride = 30;
+        newDisplayInfo.state = STATE_OFF;
+        assertEquals(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED
+                        | LOGICAL_DISPLAY_EVENT_STATE_CHANGED,
+                mLogicalDisplayMapper.updateAndGetMaskForDisplayPropertyChanges(newDisplayInfo));
+    }
+
     /////////////////
     // Helper Methods
     /////////////////
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
index 9ea7ea7..56e4048 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt
@@ -27,6 +27,7 @@
 import org.mockito.junit.MockitoJUnit
 import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.clearInvocations
 import org.mockito.kotlin.doThrow
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
@@ -149,6 +150,29 @@
     }
 
     @Test
+    fun testTokenUnlinkToDeath_noVotes() {
+        val systemRequestObserver = SystemRequestObserver(storage)
+
+        systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+        verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+    }
+
+    @Test
+    fun testTokenUnlinkToDeath_removedVotes() {
+        val systemRequestObserver = SystemRequestObserver(storage)
+        val requestedModes = intArrayOf(1, 2, 3)
+
+        systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes)
+        systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+        clearInvocations(mockToken)
+
+        systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null)
+
+        verify(mockToken, never()).unlinkToDeath(any(), eq(0))
+    }
+
+    @Test
     fun testTokenUnlinkToDeathNotCalled_votesForOtherDisplayInStorage() {
         val systemRequestObserver = SystemRequestObserver(storage)
         val requestedModes = intArrayOf(1, 2, 3)
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 95acd75..993569f 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -78,7 +78,7 @@
         "am_flags_lib",
         "device_policy_aconfig_flags_lib",
     ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
-        "true": ["service-crashrecovery.impl"],
+        "true": ["service-crashrecovery-pre-jarjar"],
         default: [],
     }),
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 30de0e8..8dc8c14 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -67,7 +67,6 @@
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
-import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
 import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED;
 import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
@@ -152,7 +151,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.platform.test.flag.util.FlagSetException;
@@ -436,8 +434,7 @@
      */
     private void disableFlagsNotSetByAnnotation() {
         try {
-            mSetFlagsRule.disableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS,
-                    Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS);
+            mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS);
         } catch (FlagSetException fse) {
             // Expected if the test about to be run requires this enabled.
         }
@@ -523,13 +520,11 @@
 
         mService.onStart();
 
-        if (Flags.useFrozenStateToDropListenerAlarms()) {
-            final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor =
-                    ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class);
-            verify(mActivityManager).registerUidFrozenStateChangedCallback(
-                    any(HandlerExecutor.class), frozenCaptor.capture());
-            mUidFrozenStateCallback = frozenCaptor.getValue();
-        }
+        final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor =
+                ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class);
+        verify(mActivityManager).registerUidFrozenStateChangedCallback(
+                any(HandlerExecutor.class), frozenCaptor.capture());
+        mUidFrozenStateCallback = frozenCaptor.getValue();
 
         // Unable to mock mMockContext to return a mock stats manager.
         // So just mocking the whole MetricsHelper instance.
@@ -3744,79 +3739,11 @@
         testTemporaryQuota_bumpedBeforeDeferral(STANDBY_BUCKET_RARE);
     }
 
-    @Test
-    public void exactListenerAlarmsRemovedOnCached() {
-        mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true);
-
-        setTestAlarmWithListener(ELAPSED_REALTIME, 31, getNewListener(() -> {}), WINDOW_EXACT,
-                TEST_CALLING_UID);
-        setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID);
-        setTestAlarm(ELAPSED_REALTIME, 54, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
-                TEST_CALLING_UID, null);
-        setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null);
-
-        setTestAlarmWithListener(ELAPSED_REALTIME, 21, getNewListener(() -> {}), WINDOW_EXACT,
-                TEST_CALLING_UID_2);
-        setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2);
-        setTestAlarm(ELAPSED_REALTIME, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
-                TEST_CALLING_UID_2, null);
-        setTestAlarm(RTC, 549, 234, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null);
-
-        assertEquals(8, mService.mAlarmStore.size());
-
-        mListener.handleUidCachedChanged(TEST_CALLING_UID, true);
-        assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
-        assertEquals(7, mService.mAlarmStore.size());
-
-        mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true);
-        assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
-        assertEquals(6, mService.mAlarmStore.size());
-    }
-
-    @Test
-    public void alarmCountOnListenerCached() {
-        mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true);
-
-        // Set some alarms for TEST_CALLING_UID.
-        final int numExactListenerUid1 = 14;
-        for (int i = 0; i < numExactListenerUid1; i++) {
-            setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i,
-                    getNewListener(() -> {}));
-        }
-        setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID);
-        setTestAlarm(ELAPSED_REALTIME, 54, getNewMockPendingIntent());
-        setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null);
-
-        // Set some alarms for TEST_CALLING_UID_2.
-        final int numExactListenerUid2 = 9;
-        for (int i = 0; i < numExactListenerUid2; i++) {
-            setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i,
-                    getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2);
-        }
-        setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2);
-        setTestAlarm(RTC_WAKEUP, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0,
-                TEST_CALLING_UID_2, null);
-
-        assertEquals(numExactListenerUid1 + 3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
-        assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
-
-        mListener.handleUidCachedChanged(TEST_CALLING_UID, true);
-        assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
-        assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
-        assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
-
-        mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true);
-        assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED);
-        assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
-        assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2));
-    }
-
     private void executeUidFrozenStateCallback(int[] uids, int[] frozenStates) {
         assertNotNull(mUidFrozenStateCallback);
         mUidFrozenStateCallback.onUidFrozenStateChanged(uids, frozenStates);
     }
 
-    @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS)
     @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS)
     @Test
     public void exactListenerAlarmsRemovedOnFrozen() {
@@ -3848,7 +3775,6 @@
         assertEquals(6, mService.mAlarmStore.size());
     }
 
-    @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS)
     @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS)
     @Test
     public void alarmCountOnListenerFrozen() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index dcbc234..5a872ea 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -47,10 +47,8 @@
 import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK;
 import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE;
 import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK;
-
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -80,6 +78,7 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.ApplicationThreadConstants;
 import android.app.BackgroundStartPrivileges;
 import android.app.BroadcastOptions;
 import android.app.ForegroundServiceDelegationOptions;
@@ -87,6 +86,7 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.SyncNotedAppOp;
+import android.app.backup.BackupAnnotations;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -111,6 +111,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.permission.IPermissionManager;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -133,6 +134,7 @@
 import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
 import com.android.server.am.UidObserverController.ChangeRecord;
 import com.android.server.appop.AppOpsService;
+import com.android.server.job.JobSchedulerInternal;
 import com.android.server.notification.NotificationManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ActivityTaskManagerService;
@@ -228,6 +230,7 @@
     @Mock private PackageManagerInternal mPackageManagerInternal;
     @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal;
     @Mock private NotificationManagerInternal mNotificationManagerInternal;
+    @Mock private JobSchedulerInternal mJobSchedulerInternal;
     @Mock private ContentResolver mContentResolver;
 
     private TestInjector mInjector;
@@ -249,6 +252,7 @@
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
         LocalServices.addService(ActivityTaskManagerInternal.class, mActivityTaskManagerInternal);
         LocalServices.addService(NotificationManagerInternal.class, mNotificationManagerInternal);
+        LocalServices.addService(JobSchedulerInternal.class, mJobSchedulerInternal);
 
         doReturn(new ComponentName("", "")).when(mPackageManagerInternal)
                 .getSystemUiServiceComponent();
@@ -308,6 +312,7 @@
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
         LocalServices.removeServiceForTest(NotificationManagerInternal.class);
+        LocalServices.removeServiceForTest(JobSchedulerInternal.class);
 
         if (mMockingSession != null) {
             mMockingSession.finishMocking();
@@ -1548,6 +1553,50 @@
                         eq(notificationId), anyInt());
     }
 
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void bindBackupAgent_fullBackup_shouldUseRestrictedMode_setsInFullBackup()
+            throws Exception {
+        ActivityManagerService spyAms = spy(mAms);
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = TEST_PACKAGE;
+        applicationInfo.processName = TEST_PACKAGE;
+        applicationInfo.uid = TEST_UID;
+        doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE),
+                anyLong(), anyInt());
+        ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID);
+        doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID));
+
+        spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL,
+                UserHandle.USER_SYSTEM,
+                BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */
+                true);
+
+        assertThat(appRec.isInFullBackup()).isTrue();
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void bindBackupAgent_fullBackup_shouldNotUseRestrictedMode_doesNotSetInFullBackup()
+            throws Exception {
+        ActivityManagerService spyAms = spy(mAms);
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = TEST_PACKAGE;
+        applicationInfo.processName = TEST_PACKAGE;
+        applicationInfo.uid = TEST_UID;
+        doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE),
+                anyLong(), anyInt());
+        ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID);
+        doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID));
+
+        spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL,
+                UserHandle.USER_SYSTEM,
+                BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */
+                false);
+
+        assertThat(appRec.isInFullBackup()).isFalse();
+    }
+
     private static class TestHandler extends Handler {
         private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec
         private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
index a1a8b0e..5eb23a2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java
@@ -58,6 +58,7 @@
 import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.Rule;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -185,10 +186,10 @@
 
         doReturn(mAppStartInfoTracker).when(mProcessList).getAppStartInfoTracker();
 
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt());
+        doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
+        doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class));
     }
 
     public void tearDown() throws Exception {
@@ -298,7 +299,7 @@
         filter.setPriority(priority);
         final BroadcastFilter res = new BroadcastFilter(filter, receiverList,
                 receiverList.app.info.packageName, null, null, null, receiverList.uid,
-                receiverList.userId, false, false, true,
+                receiverList.userId, false, false, true, receiverList.app.info,
                 mock(PlatformCompat.class));
         receiverList.add(res);
         return res;
@@ -308,4 +309,8 @@
         app.mOptRecord.setPendingFreeze(pendingFreeze);
         app.mOptRecord.setFrozen(frozen);
     }
+
+    ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) {
+        return test -> (test.uid == uid);
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
index e977a7d..5d106ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java
@@ -20,10 +20,13 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
+import android.content.pm.ApplicationInfo;
 import android.os.Process;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
@@ -53,14 +56,14 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
+        doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
     }
 
     @Test
     @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
     public void testCalculateAdjustedPriority() {
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
-
         {
             // Pairs of {initial-priority, expected-adjusted-priority}
             final Pair<Integer, Integer>[] priorities = new Pair[] {
@@ -95,8 +98,8 @@
     @Test
     @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
     public void testCalculateAdjustedPriority_withChangeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
 
         {
             // Pairs of {initial-priority, expected-adjusted-priority}
@@ -132,9 +135,6 @@
     @Test
     @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
     public void testCalculateAdjustedPriority_withFlagDisabled() {
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
-
         {
             // Pairs of {initial-priority, expected-adjusted-priority}
             final Pair<Integer, Integer>[] priorities = new Pair[] {
@@ -170,7 +170,7 @@
     @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES)
     public void testCalculateAdjustedPriority_withFlagDisabled_withChangeIdDisabled() {
         doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt());
+                eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), anyInt());
 
         {
             // Pairs of {initial-priority, expected-adjusted-priority}
@@ -215,6 +215,7 @@
         final String errorMsg = String.format("owner=%d; actualPriority=%d; expectedPriority=%d",
                 owningUid, priority, expectedAdjustedPriority);
         assertWithMessage(errorMsg).that(BroadcastFilter.calculateAdjustedPriority(
-                owningUid, priority, mPlatformCompat)).isEqualTo(expectedAdjustedPriority);
+                owningUid, priority, mock(ApplicationInfo.class), mPlatformCompat))
+                        .isEqualTo(expectedAdjustedPriority);
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 1481085..82237bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -47,6 +47,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
@@ -184,7 +185,10 @@
     }
 
     private static BroadcastFilter makeMockRegisteredReceiver() {
-        return mock(BroadcastFilter.class);
+        final BroadcastFilter filter = mock(BroadcastFilter.class);
+        final ApplicationInfo info = makeApplicationInfo(PACKAGE_ORANGE);
+        doReturn(info).when(filter).getApplicationInfo();
+        return filter;
     }
 
     private BroadcastRecord makeBroadcastRecord(Intent intent) {
@@ -716,9 +720,9 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testRunnableAt_Cached_Prioritized_NonDeferrable_changeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
         final List receivers = List.of(
                 withPriority(makeManifestReceiver(PACKAGE_RED, PACKAGE_RED), 10),
                 withPriority(makeManifestReceiver(PACKAGE_GREEN, PACKAGE_GREEN), -10));
@@ -1288,9 +1292,9 @@
     @SuppressWarnings("GuardedBy")
     @Test
     public void testDeliveryGroupPolicy_prioritized_diffReceivers_changeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
 
         final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
         final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
@@ -1823,9 +1827,9 @@
     @SuppressWarnings("GuardedBy")
     @Test
     public void testDeliveryDeferredForCached_changeIdDisabled() throws Exception {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
 
         final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN));
         final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED));
@@ -2027,9 +2031,9 @@
     @Test
     public void testDeliveryDeferredForCached_withInfiniteDeferred_changeIdDisabled()
             throws Exception {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN))));
         final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN));
         final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED));
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 9d92d5f..ea80f28 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -1659,8 +1659,9 @@
         final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
         final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
 
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(receiverBlueApp.uid)));
 
         // Enqueue a normal broadcast that will go to several processes, and
         // then enqueue a foreground broadcast that risks reordering
@@ -2471,8 +2472,9 @@
         final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
         final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
 
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
+                argThat(appInfoEquals(receiverBlueApp.uid)));
 
         mUidObserver.onUidStateChanged(receiverGreenApp.info.uid,
                 ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index a424bfdb..8482fd6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -19,12 +19,12 @@
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.server.am.BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE;
 import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED;
 import static com.android.server.am.BroadcastRecord.DELIVERY_DELIVERED;
 import static com.android.server.am.BroadcastRecord.DELIVERY_PENDING;
 import static com.android.server.am.BroadcastRecord.DELIVERY_SKIPPED;
 import static com.android.server.am.BroadcastRecord.DELIVERY_TIMEOUT;
+import static com.android.server.am.BroadcastRecord.LIMIT_PRIORITY_SCOPE;
 import static com.android.server.am.BroadcastRecord.calculateBlockedUntilBeyondCount;
 import static com.android.server.am.BroadcastRecord.calculateDeferUntilActive;
 import static com.android.server.am.BroadcastRecord.calculateUrgent;
@@ -35,7 +35,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.app.BackgroundStartPrivileges;
@@ -63,6 +64,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnitRunner;
@@ -108,8 +110,8 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt());
+        doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class));
     }
 
     @Test
@@ -222,8 +224,8 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testIsPrioritized_withDifferentPriorities_withFirstUidChangeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
 
         assertTrue(isPrioritized(List.of(
                 createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -256,8 +258,8 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testIsPrioritized_withDifferentPriorities_withLastUidChangeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3))));
 
         assertTrue(isPrioritized(List.of(
                 createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -294,8 +296,8 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testIsPrioritized_withDifferentPriorities_withUidChangeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
 
         assertTrue(isPrioritized(List.of(
                 createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -328,10 +330,10 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testIsPrioritized_withDifferentPriorities_withMultipleUidChangeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
 
         assertTrue(isPrioritized(List.of(
                 createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -362,10 +364,10 @@
         assertArrayEquals(new int[] {0, 0, 1, 1, 3},
                 calculateBlockedUntilBeyondCount(List.of(
                         createResolveInfo(PACKAGE1, getAppId(1), 20),
-                        createResolveInfo(PACKAGE2, getAppId(3), 20),
+                        createResolveInfo(PACKAGE3, getAppId(3), 20),
                         createResolveInfo(PACKAGE3, getAppId(3), 10),
                         createResolveInfo(PACKAGE3, getAppId(3), 0),
-                        createResolveInfo(PACKAGE3, getAppId(2), 0)), false, mPlatformCompat));
+                        createResolveInfo(PACKAGE2, getAppId(2), 0)), false, mPlatformCompat));
     }
 
     @Test
@@ -592,8 +594,8 @@
     @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE)
     @Test
     public void testSetDeliveryState_DeferUntilActive_changeIdDisabled() {
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
         final BroadcastRecord r = createBroadcastRecord(
                 new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of(
                         createResolveInfo(PACKAGE1, getAppId(1), 10),
@@ -960,8 +962,8 @@
                         createResolveInfo(PACKAGE2, getAppId(2)),
                         createResolveInfo(PACKAGE3, getAppId(3)))));
 
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1))));
         assertArrayEquals(new boolean[] {false, true, true}, calculateChangeState(
                 List.of(createResolveInfo(PACKAGE1, getAppId(1)),
                         createResolveInfo(PACKAGE2, getAppId(2)),
@@ -969,11 +971,11 @@
         assertArrayEquals(new boolean[] {false, true, false, true}, calculateChangeState(
                 List.of(createResolveInfo(PACKAGE1, getAppId(1)),
                         createResolveInfo(PACKAGE2, getAppId(2)),
-                        createResolveInfo(PACKAGE2, getAppId(1)),
+                        createResolveInfo(PACKAGE1, getAppId(1)),
                         createResolveInfo(PACKAGE3, getAppId(3)))));
 
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2))));
         assertArrayEquals(new boolean[] {false, false, true}, calculateChangeState(
                 List.of(createResolveInfo(PACKAGE1, getAppId(1)),
                         createResolveInfo(PACKAGE2, getAppId(2)),
@@ -987,8 +989,8 @@
                                 createResolveInfo(PACKAGE2, getAppId(2)),
                                 createResolveInfo(PACKAGE3, getAppId(3)))));
 
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3)));
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3))));
         assertArrayEquals(new boolean[] {false, false, false}, calculateChangeState(
                 List.of(createResolveInfo(PACKAGE1, getAppId(1)),
                         createResolveInfo(PACKAGE2, getAppId(2)),
@@ -998,14 +1000,14 @@
                         List.of(createResolveInfo(PACKAGE1, getAppId(1)),
                                 createResolveInfo(PACKAGE3, getAppId(3)),
                                 createResolveInfo(PACKAGE2, getAppId(2)),
-                                createResolveInfo(PACKAGE2, getAppId(1)),
+                                createResolveInfo(PACKAGE1, getAppId(1)),
                                 createResolveInfo(PACKAGE2, getAppId(2)),
                                 createResolveInfo(PACKAGE3, getAppId(3)))));
     }
 
     private boolean[] calculateChangeState(List<Object> receivers) {
         return BroadcastRecord.calculateChangeStateForReceivers(receivers,
-                CHANGE_LIMIT_PRIORITY_SCOPE, mPlatformCompat);
+                LIMIT_PRIORITY_SCOPE, mPlatformCompat);
     }
 
     private static void cleanupDisabledPackageReceivers(BroadcastRecord record,
@@ -1185,4 +1187,8 @@
         assertEquals("deferred", expectedDeferredCount, r.deferredCount);
         assertEquals("beyond", expectedBeyondCount, r.beyondCount);
     }
+
+    private ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) {
+        return test -> (test.uid == uid);
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index f82a860..a9569b4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1427,6 +1427,31 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_Service_NotPerceptible_AboveClient() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        ProcessRecord service = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
+        bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
+        mProcessStateController.setRunningRemoteAnimation(client, true);
+        mProcessStateController.updateHasAboveClientLocked(app.mServices);
+        setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE);
+        updateOomAdj(client, app, service);
+
+        final int expectedAdj;
+        if (Flags.addModifyRawOomAdjServiceLevel()) {
+            expectedAdj = SERVICE_ADJ;
+        } else {
+            expectedAdj = CACHED_APP_MIN_ADJ;
+        }
+        assertEquals(expectedAdj, app.mState.getSetAdj());
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_Service_NotVisible() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
@@ -2906,7 +2931,7 @@
         // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
         // verify that its OOM adjustment level is unaffected.
         bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
-        app.mServices.updateHasAboveClientLocked();
+        mProcessStateController.updateHasAboveClientLocked(app.mServices);
         assertTrue(app.mServices.hasAboveClient());
 
         updateOomAdj(app);
@@ -2928,7 +2953,7 @@
         // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and
         // verify that its OOM adjustment level is unaffected.
         bindService(app, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
-        app.mServices.updateHasAboveClientLocked();
+        mProcessStateController.updateHasAboveClientLocked(app.mServices);
         assertFalse(app.mServices.hasAboveClient());
 
         updateOomAdj(app);
@@ -2983,7 +3008,7 @@
 
         // Since sr.app is null, this service cannot be in the same process as the
         // client so we expect the BIND_ABOVE_CLIENT adjustment to take effect.
-        app.mServices.updateHasAboveClientLocked();
+        mProcessStateController.updateHasAboveClientLocked(app.mServices);
         updateOomAdj(app);
         assertTrue(app.mServices.hasAboveClient());
         assertNotEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -3306,7 +3331,7 @@
         if (Flags.pushGlobalStateToOomadjuster()) {
             mProcessStateController.setBackupTarget(app, app.userId);
         } else {
-            BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
+            BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0, true);
             backupTarget.app = app;
             doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
         }
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 65286d9..07f2188 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -18,9 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -32,20 +30,27 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.ApplicationThreadConstants;
+import android.app.IActivityManager;
 import android.app.backup.BackupAgent;
-import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
 import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Handler;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.testing.TestableContext;
 import android.util.FeatureFlagUtils;
@@ -68,7 +73,9 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -77,8 +84,12 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 import java.util.function.IntConsumer;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class UserBackupManagerServiceTest {
@@ -88,6 +99,11 @@
     private static final int WORKER_THREAD_TIMEOUT_MILLISECONDS = 100;
     @UserIdInt private static final int USER_ID = 0;
 
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock IBackupManagerMonitor mBackupManagerMonitor;
     @Mock IBackupObserver mBackupObserver;
     @Mock PackageManager mPackageManager;
@@ -99,10 +115,14 @@
     @Mock JobScheduler mJobScheduler;
     @Mock BackupHandler mBackupHandler;
     @Mock BackupManagerMonitorEventSender mBackupManagerMonitorEventSender;
+    @Mock IActivityManager mActivityManager;
+    @Mock
+    ActivityManagerInternal mActivityManagerInternal;
 
     private TestableContext mContext;
     private MockitoSession mSession;
     private TestBackupService mService;
+    private ApplicationInfo mTestPackageApplicationInfo;
 
     @Before
     public void setUp() throws Exception {
@@ -120,12 +140,14 @@
         mContext.getTestablePermissions().setPermission(android.Manifest.permission.BACKUP,
                 PackageManager.PERMISSION_GRANTED);
 
-        mService = new TestBackupService(mContext, mPackageManager, mOperationStorage,
-                mTransportManager, mBackupHandler);
+        mService = new TestBackupService();
         mService.setEnabled(true);
         mService.setSetupComplete(true);
         mService.enqueueFullBackup("com.test.backup.app", /* lastBackedUp= */ 0);
-        }
+
+        mTestPackageApplicationInfo = new ApplicationInfo();
+        mTestPackageApplicationInfo.packageName = TEST_PACKAGE;
+    }
 
     @After
     public void tearDown() {
@@ -298,9 +320,160 @@
                 new DataTypeResult(/* dataType */ "type_2"));
         mService.reportDelayedRestoreResult(TEST_PACKAGE, results);
 
-
         verify(mBackupManagerMonitorEventSender).sendAgentLoggingResults(
-                eq(packageInfo), eq(results), eq(BackupAnnotations.OperationType.RESTORE));
+                eq(packageInfo), eq(results), eq(OperationType.RESTORE));
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode()
+            throws Exception {
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(true));
+        // Make sure we never hit the code that checks the property.
+        verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_keyValueBackup_shouldNotUseRestrictedMode()
+            throws Exception {
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
+        // Make sure we never hit the code that checks the property.
+        verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_keyValueRestore_shouldNotUseRestrictedMode()
+            throws Exception {
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_RESTORE, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
+        // Make sure we never hit the code that checks the property.
+        verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_packageOptedIn_shouldUseRestrictedMode()
+            throws Exception {
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenReturn(new PackageManager.Property(
+                PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ true,
+                TEST_PACKAGE, /* className= */ null));
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(true));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_packageOptedOut_shouldNotUseRestrictedMode()
+            throws Exception {
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenReturn(new PackageManager.Property(
+                PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ false,
+                TEST_PACKAGE, /* className= */ null));
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    @DisableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode()
+            throws Exception {
+        // Mock that the app has not explicitly set the property.
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenThrow(
+                    new PackageManager.NameNotFoundException()
+        );
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(true));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode()
+            throws Exception {
+        // Mock that the app has not explicitly set the property.
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenThrow(
+                    new PackageManager.NameNotFoundException()
+        );
+        mService.clearNoRestrictedModePackages();
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(true));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode()
+            throws Exception {
+        // Mock that the app has not explicitly set the property.
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenThrow(
+                    new PackageManager.NameNotFoundException()
+        );
+        mService.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.RESTORE);
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode()
+            throws Exception {
+        // Mock that the app has not explicitly set the property.
+        when(mPackageManager.getPropertyAsUser(
+                eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE),
+                eq(TEST_PACKAGE), any(), anyInt())).thenThrow(
+                    new PackageManager.NameNotFoundException()
+        );
+        mService.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.BACKUP);
+
+        mService.bindToAgentSynchronous(mTestPackageApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
     }
 
     private static PackageInfo getPackageInfo(String packageName) {
@@ -316,11 +489,9 @@
 
         private volatile Thread mWorkerThread = null;
 
-        TestBackupService(Context context, PackageManager packageManager,
-                LifecycleOperationStorage operationStorage, TransportManager transportManager,
-                BackupHandler backupHandler) {
-            super(context, packageManager, operationStorage, transportManager, backupHandler,
-                    createConstants(context));
+        TestBackupService() {
+            super(mContext, mPackageManager, mOperationStorage, mTransportManager, mBackupHandler,
+                    createConstants(mContext), mActivityManager, mActivityManagerInternal);
         }
 
         private static BackupManagerConstants createConstants(Context context) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
index 9474253..3310573 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java
@@ -18,34 +18,95 @@
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.when;
 
+import android.app.backup.BackupAnnotations;
+import android.app.backup.BackupTransport;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.backup.BackupAgentTimeoutParameters;
+import com.android.server.backup.OperationStorage;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.UserBackupManagerService;
+import com.android.server.backup.transport.BackupTransportClient;
+import com.android.server.backup.transport.TransportConnection;
+import com.android.server.backup.utils.BackupEligibilityRules;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class PerformFullTransportBackupTaskTest {
+    private static final String TEST_PACKAGE_1 = "package1";
+    private static final String TEST_PACKAGE_2 = "package2";
+
+    @Mock
+    BackupAgentTimeoutParameters mBackupAgentTimeoutParameters;
+    @Mock
+    BackupEligibilityRules mBackupEligibilityRules;
     @Mock
     UserBackupManagerService mBackupManagerService;
     @Mock
+    BackupTransportClient mBackupTransportClient;
+    @Mock
+    CountDownLatch mLatch;
+    @Mock
+    OperationStorage mOperationStorage;
+    @Mock
+    PackageManager mPackageManager;
+    @Mock
+    TransportConnection mTransportConnection;
+    @Mock
     TransportManager mTransportManager;
+    @Mock
+    UserBackupManagerService.BackupWakeLock mWakeLock;
+
+    private final List<String> mEligiblePackages = new ArrayList<>();
+
+    private PerformFullTransportBackupTask mTask;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        when(mBackupManagerService.getPackageManager()).thenReturn(mPackageManager);
+        when(mBackupManagerService.getQueueLock()).thenReturn("something!");
+        when(mBackupManagerService.isEnabled()).thenReturn(true);
+        when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
+        when(mBackupManagerService.isSetupComplete()).thenReturn(true);
+        when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(
+                mBackupAgentTimeoutParameters);
         when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager);
+        when(mTransportManager.getCurrentTransportClient(any())).thenReturn(mTransportConnection);
+        when(mTransportConnection.connectOrThrow(any())).thenReturn(mBackupTransportClient);
+        when(mTransportConnection.connect(any())).thenReturn(mBackupTransportClient);
+        when(mBackupTransportClient.performFullBackup(any(), any(), anyInt())).thenReturn(
+                BackupTransport.TRANSPORT_ERROR);
+        when(mBackupEligibilityRules.appIsEligibleForBackup(
+                argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn(
+                true);
+        when(mBackupEligibilityRules.appGetsFullBackup(
+                argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn(
+                true);
     }
 
     @Test
@@ -70,4 +131,49 @@
                                     /* backupEligibilityRules */  null);
                 });
     }
+
+    @Test
+    public void run_setsAndClearsNoRestrictedModePackages() throws Exception {
+        mockPackageEligibleForFullBackup(TEST_PACKAGE_1);
+        mockPackageEligibleForFullBackup(TEST_PACKAGE_2);
+        createTask(new String[] {TEST_PACKAGE_1, TEST_PACKAGE_2});
+        when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(),
+                anyInt())).thenReturn(Set.of("package1"));
+
+        mTask.run();
+
+        InOrder inOrder = inOrder(mBackupManagerService);
+        inOrder.verify(mBackupManagerService).setNoRestrictedModePackages(
+                eq(Set.of("package1")),
+                eq(BackupAnnotations.OperationType.BACKUP));
+        inOrder.verify(mBackupManagerService).clearNoRestrictedModePackages();
+    }
+
+    private void createTask(String[] packageNames) {
+        mTask = PerformFullTransportBackupTask
+                .newWithCurrentTransport(
+                        mBackupManagerService,
+                        mOperationStorage,
+                        /* observer */  null,
+                        /* whichPackages */  packageNames,
+                        /* updateSchedule */  false,
+                        /* runningJob */  null,
+                        mLatch,
+                        /* backupObserver */  null,
+                        /* monitor */  null,
+                        /* userInitiated */  false,
+                        /* caller */  null,
+                        mBackupEligibilityRules);
+    }
+
+    private void mockPackageEligibleForFullBackup(String packageName) throws Exception {
+        mEligiblePackages.add(packageName);
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = packageName;
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = packageName;
+        packageInfo.applicationInfo = appInfo;
+        when(mPackageManager.getPackageInfoAsUser(eq(packageName), anyInt(), anyInt())).thenReturn(
+                packageInfo);
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
index 414532b..055adf6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
@@ -23,8 +23,10 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupTransport;
@@ -91,6 +93,8 @@
     private UserBackupManagerService mBackupManagerService;
     @Mock
     private TransportConnection mTransportConnection;
+    @Mock
+    private BackupTransportClient mBackupTransportClient;
 
     private Set<String> mExcludedkeys = new HashSet<>();
     private Map<String, String> mBackupData = new HashMap<>();
@@ -151,6 +155,23 @@
     }
 
     @Test
+    public void setNoRestrictedModePackages_callsTransportAndSetsValue() throws Exception {
+        PackageInfo packageInfo1 = new PackageInfo();
+        packageInfo1.packageName = "package1";
+        PackageInfo packageInfo2 = new PackageInfo();
+        packageInfo2.packageName = "package2";
+        when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(),
+                anyInt())).thenReturn(Set.of("package1"));
+
+        mRestoreTask.setNoRestrictedModePackages(mBackupTransportClient,
+                new PackageInfo[]{packageInfo1, packageInfo2});
+
+        verify(mBackupManagerService).setNoRestrictedModePackages(
+                eq(Set.of("package1")),
+                eq(BackupAnnotations.OperationType.RESTORE));
+    }
+
+    @Test
     public void testFilterExcludedKeys() throws Exception {
         when(mBackupManagerService.getExcludedRestoreKeys(eq(PACKAGE_NAME)))
                 .thenReturn(mExcludedkeys);
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
index 2d7d46f..13e3207 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java
@@ -19,7 +19,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
 
+import android.app.backup.BackupAnnotations.OperationType;
 import android.app.backup.BackupTransport;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.RestoreDescription;
@@ -38,15 +45,31 @@
 import com.android.internal.backup.ITransportStatusCallback;
 import com.android.internal.infra.AndroidFuture;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.List;
+import java.util.Set;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 public class BackupTransportClientTest {
 
+    @Mock
+    IBackupTransport mMockBackupTransport;
+
+    private BackupTransportClient mMockingTransportClient;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mMockingTransportClient = new BackupTransportClient(
+                mMockBackupTransport);
+    }
+
     private static class TestFuturesFakeTransportBinder extends FakeTransportBinderBase {
         public final Object mLock = new Object();
 
@@ -128,6 +151,70 @@
         thread.join();
     }
 
+    @Test
+    public void getPackagesThatShouldNotUseRestrictedMode_passesSetAsListToBinder()
+            throws Exception {
+        mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2"));
+
+        mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+                Set.of("package1", "package2"),
+                OperationType.BACKUP);
+
+        verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(
+                argThat(list -> Set.copyOf(list).equals(Set.of("package1", "package2"))),
+                eq(OperationType.BACKUP), any());
+    }
+
+    @Test
+    public void getPackagesThatShouldNotUseRestrictedMode_forRestore_callsBinderForRestore()
+            throws Exception {
+        mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+        mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+                Set.of(),
+                OperationType.RESTORE);
+
+        verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(),
+                eq(OperationType.RESTORE), any());
+    }
+
+    @Test
+    public void getPackagesThatShouldNotUseRestrictedMode_forBackup_callsBinderForBackup()
+            throws Exception {
+        mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+        mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+                Set.of(),
+                OperationType.BACKUP);
+
+        verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(),
+                eq(OperationType.BACKUP), any());
+    }
+
+    @Test
+    public void getPackagesThatShouldNotUseRestrictedMode_nullResult_returnsEmptySet()
+            throws Exception {
+        mockGetPackagesThatShouldNotUseRestrictedModeReturn(null);
+
+        Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+                Set.of(),
+                OperationType.BACKUP);
+
+        assertThat(result).isEqualTo(Set.of());
+    }
+
+    @Test
+    public void getPackagesThatShouldNotUseRestrictedMode_returnsResultAsSet()
+            throws Exception {
+        mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2"));
+
+        Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode(
+                Set.of("package1", "package2"),
+                OperationType.BACKUP);
+
+        assertThat(result).isEqualTo(Set.of("package1", "package2"));
+    }
+
     private static class TestCallbacksFakeTransportBinder extends FakeTransportBinderBase {
         public final Object mLock = new Object();
 
@@ -158,7 +245,6 @@
         assertThat(status).isEqualTo(123);
     }
 
-
     @Test
     public void testFinishBackup_completesLater_returnsStatus() throws Exception {
         TestCallbacksFakeTransportBinder binder = new TestCallbacksFakeTransportBinder();
@@ -211,6 +297,14 @@
         thread.join();
     }
 
+    private void mockGetPackagesThatShouldNotUseRestrictedModeReturn(List<String> returnList)
+            throws Exception {
+        doAnswer(
+                i -> ((AndroidFuture<List<String>>) i.getArguments()[2]).complete(returnList)).when(
+                mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(), anyInt(),
+                any());
+    }
+
     // Convenience layer so we only need to fake specific methods useful for each test case.
     private static class FakeTransportBinderBase implements IBackupTransport {
         @Override public void name(AndroidFuture<String> f) throws RemoteException {}
@@ -258,6 +352,10 @@
         @Override
         public void getBackupManagerMonitor(AndroidFuture<IBackupManagerMonitor> resultFuture)
                 throws RemoteException {}
+        @Override
+        public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames,
+                int operationType, AndroidFuture<List<String>> resultFuture)
+                throws RemoteException {}
         @Override public IBinder asBinder() {
             return null;
         }
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
index 1f88c29..8eae9c7d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -37,7 +37,7 @@
         "truth",
         "flag-junit",
     ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
-        "true": ["service-crashrecovery.impl"],
+        "true": ["service-crashrecovery-pre-jarjar"],
         default: [],
     }),
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
index f6c644e..20ac078 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ApkLite;
 import android.content.pm.parsing.ApkLiteParseUtils;
@@ -34,6 +35,8 @@
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.OutcomeReceiver;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -71,13 +74,17 @@
     private static final String PUSH_FILE_DIR = "/data/local/tmp/tests/smockingservicestest/pm/";
     private static final String TEST_APP_USING_SDK1_AND_SDK2 = "HelloWorldUsingSdk1And2.apk";
 
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
     @Mock private SharedLibrariesImpl mSharedLibraries;
+    @Mock private Context mContext;
+    @Mock private Computer mComputer;
     private InstallDependencyHelper mInstallDependencyHelper;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInstallDependencyHelper = new InstallDependencyHelper(mSharedLibraries);
+        mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries);
     }
 
     @Test
@@ -88,7 +95,8 @@
 
         PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2);
         CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false);
-        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+                0, mHandler, callback);
         callback.assertFailure();
 
         assertThat(callback.error).hasMessageThat().contains("xyz");
@@ -104,11 +112,12 @@
                 .thenReturn(missingDependency);
 
         CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false);
-        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+                0, mHandler, callback);
         callback.assertFailure();
 
         assertThat(callback.error).hasMessageThat().contains(
-                "Failed to bind to Dependency Installer");
+                "Dependency Installer Service not found");
     }
 
 
@@ -121,7 +130,8 @@
                 .thenReturn(missingDependency);
 
         CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ true);
-        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback);
+        mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer,
+                0, mHandler, callback);
         callback.assertSuccess();
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
index 2f23e02..5a802d9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
@@ -35,7 +35,7 @@
         "truth",
         "flag-junit",
     ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
-        "true": ["service-crashrecovery.impl"],
+        "true": ["service-crashrecovery-pre-jarjar"],
         default: [],
     }),
 
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 58489f3..0881b4c 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 
 import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS;
+import static com.android.server.power.hint.HintManagerService.DEFAULT_HEADROOM_PID;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -51,11 +52,15 @@
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.power.ChannelConfig;
 import android.hardware.power.ChannelMessage;
+import android.hardware.power.CpuHeadroomParams;
+import android.hardware.power.GpuHeadroomParams;
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
 import android.hardware.power.WorkDuration;
 import android.os.Binder;
+import android.os.CpuHeadroomParamsInternal;
+import android.os.GpuHeadroomParamsInternal;
 import android.os.IBinder;
 import android.os.IHintSession;
 import android.os.PerformanceHintManager;
@@ -128,11 +133,11 @@
     private static final long[] TIMESTAMPS_ZERO = new long[] {};
     private static final long[] TIMESTAMPS_TWO = new long[] {1L, 2L};
     private static final WorkDuration[] WORK_DURATIONS_FIVE = new WorkDuration[] {
-        makeWorkDuration(1L, 11L, 1L, 8L, 4L),
-        makeWorkDuration(2L, 13L, 2L, 8L, 6L),
-        makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L),
-        makeWorkDuration(2L, 13L, 2L, 0L, 6L),
-        makeWorkDuration(2L, 13L, 2L, 8L, 0L),
+            makeWorkDuration(1L, 11L, 1L, 8L, 4L),
+            makeWorkDuration(2L, 13L, 2L, 8L, 6L),
+            makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L),
+            makeWorkDuration(2L, 13L, 2L, 0L, 6L),
+            makeWorkDuration(2L, 13L, 2L, 8L, 0L),
     };
     private static final String TEST_APP_NAME = "com.android.test.app";
 
@@ -187,17 +192,17 @@
         when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
                 eq(SESSION_TIDS_A), eq(DEFAULT_TARGET_DURATION), anyInt(),
                 any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[0],
-                    SESSION_IDS[0]));
+                SESSION_IDS[0]));
         when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
                 eq(SESSION_TIDS_B), eq(DOUBLED_TARGET_DURATION), anyInt(),
                 any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[1],
-                    SESSION_IDS[1]));
+                SESSION_IDS[1]));
         when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID),
                 eq(SESSION_TIDS_C), eq(0L), anyInt(),
                 any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[2],
-                    SESSION_IDS[2]));
+                SESSION_IDS[2]));
 
-        when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
+        when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
         when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
         LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
@@ -217,8 +222,8 @@
         when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_C),
                 eq(0L))).thenReturn(SESSION_PTRS[2]);
         when(mNativeWrapperMock.halCreateHintSessionWithConfig(anyInt(), anyInt(),
-            any(int[].class), anyLong(), anyInt(),
-            any(SessionConfig.class))).thenThrow(new UnsupportedOperationException());
+                any(int[].class), anyLong(), anyInt(),
+                any(SessionConfig.class))).thenThrow(new UnsupportedOperationException());
     }
 
     static class NativeWrapperFake extends NativeWrapper {
@@ -337,7 +342,7 @@
                 SESSION_TIDS_C, 0L, SessionTag.OTHER, new SessionConfig());
         assertNotNull(c);
         verify(mNativeWrapperMock, times(3)).halCreateHintSession(anyInt(), anyInt(),
-                                                                  any(int[].class), anyLong());
+                any(int[].class), anyLong());
     }
 
     @Test
@@ -487,7 +492,7 @@
 
         AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
                 .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
-                    SessionTag.OTHER, new SessionConfig());
+                        SessionTag.OTHER, new SessionConfig());
 
         a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
         verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(),
@@ -514,7 +519,7 @@
 
         AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
                 .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION,
-                    SessionTag.OTHER, new SessionConfig());
+                        SessionTag.OTHER, new SessionConfig());
 
         service.mUidObserver.onUidStateChanged(
                 a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
@@ -1096,4 +1101,157 @@
         verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID));
         assertTrue(service.hasChannel(TGID, UID));
     }
+
+    @Test
+    public void testHeadroomPowerHalNotSupported() throws Exception {
+        when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
+        HintManagerService service = createService();
+        assertThrows(UnsupportedOperationException.class, () -> {
+            service.getBinderServiceInstance().getCpuHeadroom(null);
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            service.getBinderServiceInstance().getGpuHeadroom(null);
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
+        });
+    }
+
+    @Test
+    public void testCpuHeadroomCache() throws Exception {
+        when(mIPowerMock.getCpuHeadroomMinIntervalMillis()).thenReturn(2000L);
+        CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal();
+        CpuHeadroomParams halParams1 = new CpuHeadroomParams();
+        halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN;
+        halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL;
+        halParams1.pid = Process.myPid();
+
+        CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal();
+        params2.usesDeviceHeadroom = true;
+        params2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+        CpuHeadroomParams halParams2 = new CpuHeadroomParams();
+        halParams2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
+        halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
+        halParams2.pid = DEFAULT_HEADROOM_PID;
+
+        float[] headroom1 = new float[] {0.1f};
+        when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(headroom1);
+        float[] headroom2 = new float[] {0.1f, 0.5f};
+        when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+
+        HintManagerService service = createService();
+        clearInvocations(mIPowerMock);
+
+        service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
+        verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis();
+        service.getBinderServiceInstance().getCpuHeadroom(params1);
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
+        service.getBinderServiceInstance().getCpuHeadroom(params2);
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+
+        // verify cache is working
+        clearInvocations(mIPowerMock);
+        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+                0.01f);
+        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+        // after 1 more second it should be served with cache still
+        Thread.sleep(1000);
+        clearInvocations(mIPowerMock);
+        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+                0.01f);
+        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+        // after 1.5 more second it should be served with cache still as timer reset
+        Thread.sleep(1500);
+        clearInvocations(mIPowerMock);
+        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+                0.01f);
+        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
+
+        // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
+        Thread.sleep(2100);
+        clearInvocations(mIPowerMock);
+        assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1),
+                0.01f);
+        assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2));
+    }
+
+    @Test
+    public void testGpuHeadroomCache() throws Exception {
+        when(mIPowerMock.getGpuHeadroomMinIntervalMillis()).thenReturn(2000L);
+        GpuHeadroomParamsInternal params1 = new GpuHeadroomParamsInternal();
+        GpuHeadroomParams halParams1 = new GpuHeadroomParams();
+        halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN;
+
+        GpuHeadroomParamsInternal params2 = new GpuHeadroomParamsInternal();
+        GpuHeadroomParams halParams2 = new GpuHeadroomParams();
+        params2.calculationType =
+                halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE;
+
+        float headroom1 = 0.1f;
+        when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(headroom1);
+        float headroom2 = 0.2f;
+        when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(headroom2);
+        HintManagerService service = createService();
+        clearInvocations(mIPowerMock);
+
+        service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
+        verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis();
+        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+                0.01f);
+        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+
+        // verify cache is working
+        clearInvocations(mIPowerMock);
+        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+                0.01f);
+        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+        // after 1 more second it should be served with cache still
+        Thread.sleep(1000);
+        clearInvocations(mIPowerMock);
+        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+                0.01f);
+        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+        // after 1.5 more second it should be served with cache still as timer reset
+        Thread.sleep(1500);
+        clearInvocations(mIPowerMock);
+        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+                0.01f);
+        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
+
+        // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval
+        Thread.sleep(2100);
+        clearInvocations(mIPowerMock);
+        assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1),
+                0.01f);
+        assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2),
+                0.01f);
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
+        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+    }
 }
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 359cf63..b48c2d7 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -2705,12 +2705,11 @@
         verify(mInvalidateInteractiveCachesMock).call();
 
         listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
-        verify(mInvalidateInteractiveCachesMock, times(2)).call();
 
         mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP,
                 mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
 
-        verify(mInvalidateInteractiveCachesMock, times(3)).call();
+        verify(mInvalidateInteractiveCachesMock, times(2)).call();
     }
 
     @Test
@@ -2732,12 +2731,11 @@
         verify(mInvalidateInteractiveCachesMock).call();
 
         listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
-        verify(mInvalidateInteractiveCachesMock, times(2)).call();
 
         mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, mClock.now(),
                 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null);
 
-        verify(mInvalidateInteractiveCachesMock, times(3)).call();
+        verify(mInvalidateInteractiveCachesMock, times(2)).call();
     }
 
     @Test
diff --git a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
index 40e0034..03c449c 100644
--- a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
+++ b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java
@@ -16,9 +16,13 @@
 
 package com.android.server.security.forensic;
 
+import static android.Manifest.permission.MANAGE_FORENSIC_STATE;
+import static android.Manifest.permission.READ_FORENSIC_STATE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -27,57 +31,63 @@
 import static org.mockito.Mockito.verify;
 
 import android.annotation.SuppressLint;
+import android.app.admin.ConnectEvent;
+import android.app.admin.DnsEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.Context;
 import android.os.Looper;
+import android.os.PermissionEnforcer;
 import android.os.RemoteException;
+import android.os.test.FakePermissionEnforcer;
 import android.os.test.TestLooper;
 import android.security.forensic.ForensicEvent;
 import android.security.forensic.IForensicServiceCommandCallback;
 import android.security.forensic.IForensicServiceStateCallback;
-import android.util.ArrayMap;
 
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.server.ServiceThread;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 public class ForensicServiceTest {
     private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN;
-    private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE;
-    private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE;
+    private static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED;
     private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED;
 
     private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN;
     private static final int ERROR_PERMISSION_DENIED =
             IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED;
-    private static final int ERROR_INVALID_STATE_TRANSITION =
-            IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION;
-    private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE =
-            IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE;
+    private static final int ERROR_TRANSPORT_UNAVAILABLE =
+            IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE;
     private static final int ERROR_DATA_SOURCE_UNAVAILABLE =
             IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE;
 
     private Context mContext;
-    private BackupTransportConnection mBackupTransportConnection;
+    private ForensicEventTransportConnection mForensicEventTransportConnection;
     private DataAggregator mDataAggregator;
     private ForensicService mForensicService;
     private TestLooper mTestLooper;
     private Looper mLooper;
     private TestLooper mTestLooperOfDataAggregator;
     private Looper mLooperOfDataAggregator;
+    private FakePermissionEnforcer mPermissionEnforcer;
 
     @SuppressLint("VisibleForTests")
     @Before
     public void setUp() {
         mContext = spy(ApplicationProvider.getApplicationContext());
 
+        mPermissionEnforcer = new FakePermissionEnforcer();
+        mPermissionEnforcer.grant(READ_FORENSIC_STATE);
+        mPermissionEnforcer.grant(MANAGE_FORENSIC_STATE);
+
         mTestLooper = new TestLooper();
         mLooper = mTestLooper.getLooper();
         mTestLooperOfDataAggregator = new TestLooper();
@@ -87,217 +97,101 @@
     }
 
     @Test
-    public void testMonitorState_Invisible() throws RemoteException {
+    public void testAddStateCallback_NoPermission() {
+        mPermissionEnforcer.revoke(READ_FORENSIC_STATE);
         StateCallback scb = new StateCallback();
         assertEquals(STATE_UNKNOWN, scb.mState);
-        mForensicService.getBinderService().monitorState(scb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb.mState);
+        assertThrows(SecurityException.class,
+                () -> mForensicService.getBinderService().addStateCallback(scb));
     }
 
     @Test
-    public void testMonitorState_Invisible_TwoMonitors() throws RemoteException {
+    public void testRemoveStateCallback_NoPermission() {
+        mPermissionEnforcer.revoke(READ_FORENSIC_STATE);
+        StateCallback scb = new StateCallback();
+        assertEquals(STATE_UNKNOWN, scb.mState);
+        assertThrows(SecurityException.class,
+                () -> mForensicService.getBinderService().removeStateCallback(scb));
+    }
+
+    @Test
+    public void testEnable_NoPermission() {
+        mPermissionEnforcer.revoke(MANAGE_FORENSIC_STATE);
+
+        CommandCallback ccb = new CommandCallback();
+        assertThrows(SecurityException.class,
+                () -> mForensicService.getBinderService().enable(ccb));
+    }
+
+    @Test
+    public void testDisable_NoPermission() {
+        mPermissionEnforcer.revoke(MANAGE_FORENSIC_STATE);
+
+        CommandCallback ccb = new CommandCallback();
+        assertThrows(SecurityException.class,
+                () -> mForensicService.getBinderService().disable(ccb));
+    }
+
+    @Test
+    public void testAddStateCallback_Disabled() throws RemoteException {
+        StateCallback scb = new StateCallback();
+        assertEquals(STATE_UNKNOWN, scb.mState);
+        mForensicService.getBinderService().addStateCallback(scb);
+        mTestLooper.dispatchAll();
+        assertEquals(STATE_DISABLED, scb.mState);
+    }
+
+    @Test
+    public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException {
         StateCallback scb1 = new StateCallback();
         assertEquals(STATE_UNKNOWN, scb1.mState);
-        mForensicService.getBinderService().monitorState(scb1);
+        mForensicService.getBinderService().addStateCallback(scb1);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
 
         StateCallback scb2 = new StateCallback();
         assertEquals(STATE_UNKNOWN, scb2.mState);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
     }
 
     @Test
-    public void testMakeVisible_FromInvisible() throws RemoteException {
-        StateCallback scb = new StateCallback();
-        assertEquals(STATE_UNKNOWN, scb.mState);
-        mForensicService.getBinderService().monitorState(scb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeVisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-    @Test
-    public void testMakeVisible_FromInvisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_INVISIBLE);
+    public void testRemoveStateCallback() throws RemoteException {
+        mForensicService.setState(STATE_DISABLED);
         StateCallback scb1 = new StateCallback();
         StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
 
         doReturn(true).when(mDataAggregator).initialize();
+        doReturn(true).when(mForensicEventTransportConnection).initialize();
 
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeVisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-    @Test
-    public void testMakeVisible_FromInvisible_TwoMonitors_DataSourceUnavailable()
-            throws RemoteException {
-        mForensicService.setState(STATE_INVISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-
-        doReturn(false).when(mDataAggregator).initialize();
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeVisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNotNull(ccb.mErrorCode);
-        assertEquals(ERROR_DATA_SOURCE_UNAVAILABLE, ccb.mErrorCode.intValue());
-    }
-
-    @Test
-    public void testMakeVisible_FromVisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_VISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeVisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-    @Test
-    public void testMakeVisible_FromEnabled_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_ENABLED);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_ENABLED, scb1.mState);
-        assertEquals(STATE_ENABLED, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeVisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_ENABLED, scb1.mState);
-        assertEquals(STATE_ENABLED, scb2.mState);
-        assertNotNull(ccb.mErrorCode);
-        assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
-    }
-
-    @Test
-    public void testMakeInvisible_FromInvisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_INVISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeInvisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-    @Test
-    public void testMakeInvisible_FromVisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_VISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeInvisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-    @Test
-    public void testMakeInvisible_FromEnabled_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_ENABLED);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_ENABLED, scb1.mState);
-        assertEquals(STATE_ENABLED, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().makeInvisible(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNull(ccb.mErrorCode);
-    }
-
-
-    @Test
-    public void testEnable_FromInvisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_INVISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
+        mForensicService.getBinderService().removeStateCallback(scb2);
 
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().enable(ccb);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNotNull(ccb.mErrorCode);
-        assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
+        assertEquals(STATE_ENABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
+        assertNull(ccb.mErrorCode);
     }
 
     @Test
-    public void testEnable_FromVisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_VISIBLE);
+    public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException {
+        mForensicService.setState(STATE_DISABLED);
         StateCallback scb1 = new StateCallback();
         StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
 
-        doReturn(true).when(mBackupTransportConnection).initialize();
+        doReturn(true).when(mForensicEventTransportConnection).initialize();
 
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().enable(ccb);
@@ -310,35 +204,13 @@
     }
 
     @Test
-    public void testEnable_FromVisible_TwoMonitors_BackupTransportUnavailable()
+    public void testEnable_FromEnabled_TwoStateCallbacks()
             throws RemoteException {
-        mForensicService.setState(STATE_VISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-
-        doReturn(false).when(mBackupTransportConnection).initialize();
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().enable(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-        assertNotNull(ccb.mErrorCode);
-        assertEquals(ERROR_BACKUP_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue());
-    }
-
-    @Test
-    public void testEnable_FromEnabled_TwoMonitors() throws RemoteException {
         mForensicService.setState(STATE_ENABLED);
         StateCallback scb1 = new StateCallback();
         StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
         assertEquals(STATE_ENABLED, scb1.mState);
         assertEquals(STATE_ENABLED, scb2.mState);
@@ -346,62 +218,44 @@
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().enable(ccb);
         mTestLooper.dispatchAll();
+
         assertEquals(STATE_ENABLED, scb1.mState);
         assertEquals(STATE_ENABLED, scb2.mState);
         assertNull(ccb.mErrorCode);
     }
 
     @Test
-    public void testDisable_FromInvisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_INVISIBLE);
+    public void testDisable_FromDisabled_TwoStateCallbacks() throws RemoteException {
+        mForensicService.setState(STATE_DISABLED);
         StateCallback scb1 = new StateCallback();
         StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
 
         CommandCallback ccb = new CommandCallback();
         mForensicService.getBinderService().disable(ccb);
         mTestLooper.dispatchAll();
-        assertEquals(STATE_INVISIBLE, scb1.mState);
-        assertEquals(STATE_INVISIBLE, scb2.mState);
-        assertNotNull(ccb.mErrorCode);
-        assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue());
-    }
 
-    @Test
-    public void testDisable_FromVisible_TwoMonitors() throws RemoteException {
-        mForensicService.setState(STATE_VISIBLE);
-        StateCallback scb1 = new StateCallback();
-        StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
-
-        CommandCallback ccb = new CommandCallback();
-        mForensicService.getBinderService().disable(ccb);
-        mTestLooper.dispatchAll();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
         assertNull(ccb.mErrorCode);
     }
 
     @Test
-    public void testDisable_FromEnabled_TwoMonitors() throws RemoteException {
+    public void testDisable_FromEnabled_TwoStateCallbacks() throws RemoteException {
         mForensicService.setState(STATE_ENABLED);
         StateCallback scb1 = new StateCallback();
         StateCallback scb2 = new StateCallback();
-        mForensicService.getBinderService().monitorState(scb1);
-        mForensicService.getBinderService().monitorState(scb2);
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
         mTestLooper.dispatchAll();
         assertEquals(STATE_ENABLED, scb1.mState);
         assertEquals(STATE_ENABLED, scb2.mState);
 
-        doNothing().when(mBackupTransportConnection).release();
+        doNothing().when(mForensicEventTransportConnection).release();
 
         ServiceThread mockThread = spy(ServiceThread.class);
         mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
@@ -412,56 +266,74 @@
         mTestLooperOfDataAggregator.dispatchAll();
         // TODO: We can verify the data sources once we implement them.
         verify(mockThread, times(1)).quitSafely();
-        assertEquals(STATE_VISIBLE, scb1.mState);
-        assertEquals(STATE_VISIBLE, scb2.mState);
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
         assertNull(ccb.mErrorCode);
     }
 
+    @Ignore("Enable once the ForensicEventTransportConnection is ready")
+    @Test
+    public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable()
+            throws RemoteException {
+        mForensicService.setState(STATE_DISABLED);
+        StateCallback scb1 = new StateCallback();
+        StateCallback scb2 = new StateCallback();
+        mForensicService.getBinderService().addStateCallback(scb1);
+        mForensicService.getBinderService().addStateCallback(scb2);
+        mTestLooper.dispatchAll();
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
+
+        doReturn(false).when(mForensicEventTransportConnection).initialize();
+
+        CommandCallback ccb = new CommandCallback();
+        mForensicService.getBinderService().enable(ccb);
+        mTestLooper.dispatchAll();
+        assertEquals(STATE_DISABLED, scb1.mState);
+        assertEquals(STATE_DISABLED, scb2.mState);
+        assertNotNull(ccb.mErrorCode);
+        assertEquals(ERROR_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue());
+    }
+
     @Test
     public void testDataAggregator_AddBatchData() {
         mForensicService.setState(STATE_ENABLED);
         ServiceThread mockThread = spy(ServiceThread.class);
         mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread);
 
-        String eventOneType = "event_one_type";
-        String eventOneMapKey = "event_one_map_key";
-        String eventOneMapVal = "event_one_map_val";
-        Map<String, String> eventOneMap = new ArrayMap<String, String>();
-        eventOneMap.put(eventOneMapKey, eventOneMapVal);
-        ForensicEvent eventOne = new ForensicEvent(eventOneType, eventOneMap);
+        SecurityEvent securityEvent = new SecurityEvent(0, new byte[0]);
+        ForensicEvent eventOne = new ForensicEvent(securityEvent);
 
-        String eventTwoType = "event_two_type";
-        String eventTwoMapKey = "event_two_map_key";
-        String eventTwoMapVal = "event_two_map_val";
-        Map<String, String> eventTwoMap = new ArrayMap<String, String>();
-        eventTwoMap.put(eventTwoMapKey, eventTwoMapVal);
-        ForensicEvent eventTwo = new ForensicEvent(eventTwoType, eventTwoMap);
+        ConnectEvent connectEvent = new ConnectEvent("127.0.0.1", 80, null, 0);
+        ForensicEvent eventTwo = new ForensicEvent(connectEvent);
+
+        DnsEvent dnsEvent = new DnsEvent(null, new String[] {"127.0.0.1"}, 1, null, 0);
+        ForensicEvent eventThree = new ForensicEvent(dnsEvent);
 
         List<ForensicEvent> events = new ArrayList<>();
         events.add(eventOne);
         events.add(eventTwo);
+        events.add(eventThree);
 
-        doReturn(true).when(mBackupTransportConnection).addData(any());
+        doReturn(true).when(mForensicEventTransportConnection).addData(any());
 
         mDataAggregator.addBatchData(events);
         mTestLooperOfDataAggregator.dispatchAll();
         mTestLooper.dispatchAll();
 
         ArgumentCaptor<List<ForensicEvent>> captor = ArgumentCaptor.forClass(List.class);
-        verify(mBackupTransportConnection).addData(captor.capture());
+        verify(mForensicEventTransportConnection).addData(captor.capture());
         List<ForensicEvent> receivedEvents = captor.getValue();
-        assertEquals(receivedEvents.size(), 2);
+        assertEquals(receivedEvents.size(), 3);
 
-        assertEquals(receivedEvents.getFirst().getType(), eventOneType);
-        assertEquals(receivedEvents.getFirst().getKeyValuePairs().size(), 1);
-        assertEquals(receivedEvents.getFirst().getKeyValuePairs().get(eventOneMapKey),
-                eventOneMapVal);
+        assertEquals(receivedEvents.get(0).getType(), ForensicEvent.SECURITY_EVENT);
+        assertNotNull(receivedEvents.get(0).getSecurityEvent());
 
-        assertEquals(receivedEvents.getLast().getType(), eventTwoType);
-        assertEquals(receivedEvents.getLast().getKeyValuePairs().size(), 1);
-        assertEquals(receivedEvents.getLast().getKeyValuePairs().get(eventTwoMapKey),
-                eventTwoMapVal);
+        assertEquals(receivedEvents.get(1).getType(), ForensicEvent.NETWORK_EVENT_CONNECT);
+        assertNotNull(receivedEvents.get(1).getConnectEvent());
 
+        assertEquals(receivedEvents.get(2).getType(), ForensicEvent.NETWORK_EVENT_DNS);
+        assertNotNull(receivedEvents.get(2).getDnsEvent());
     }
 
     private class MockInjector implements ForensicService.Injector {
@@ -476,6 +348,10 @@
             return mContext;
         }
 
+        @Override
+        public PermissionEnforcer getPermissionEnforcer() {
+            return mPermissionEnforcer;
+        }
 
         @Override
         public Looper getLooper() {
@@ -483,9 +359,9 @@
         }
 
         @Override
-        public BackupTransportConnection getBackupTransportConnection() {
-            mBackupTransportConnection = spy(new BackupTransportConnection(mContext));
-            return mBackupTransportConnection;
+        public ForensicEventTransportConnection getForensicEventransportConnection() {
+            mForensicEventTransportConnection = spy(new ForensicEventTransportConnection(mContext));
+            return mForensicEventTransportConnection;
         }
 
         @Override
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f165667..0c058df 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -97,7 +97,7 @@
         "com_android_server_accessibility_flags_lib",
         "locksettings_flags_lib",
     ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
-        "true": ["service-crashrecovery.impl"],
+        "true": ["service-crashrecovery-pre-jarjar"],
         default: [],
     }),
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index b81bf3c..f6f831f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -21,6 +21,7 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
 
 import static com.android.server.biometrics.sensors.LockoutTracker.LOCKOUT_NONE;
 
@@ -354,6 +355,21 @@
         assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isTrue();
     }
 
+    @Test
+    public void prioritizeStrengthErrorBeforeCameraUnavailableError() throws Exception {
+        final BiometricSensor sensor = getFaceSensorWithStrength(
+                BiometricManager.Authenticators.BIOMETRIC_WEAK);
+        final PromptInfo promptInfo = new PromptInfo();
+        promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+        promptInfo.setNegativeButtonText(TEST_PACKAGE_NAME);
+        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+                mSettingObserver, List.of(sensor), USER_ID , promptInfo, TEST_PACKAGE_NAME,
+                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
+                mUserManager);
+
+        assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
+    }
+
     private BiometricSensor getFingerprintSensor() {
         BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT,
                 TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG,
@@ -372,9 +388,10 @@
         return sensor;
     }
 
-    private BiometricSensor getFaceSensor() {
+    private BiometricSensor getFaceSensorWithStrength(
+            @BiometricManager.Authenticators.Types int sensorStrength) {
         BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
-                BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
+                sensorStrength, mFaceAuthenticator) {
             @Override
             boolean confirmationAlwaysRequired(int userId) {
                 return false;
@@ -388,4 +405,8 @@
 
         return sensor;
     }
+
+    private BiometricSensor getFaceSensor() {
+        return getFaceSensorWithStrength(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 698bda3..4c381eb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -24,6 +24,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicyManagerLiteInternal;
 import android.app.backup.IBackupManager;
+import android.app.supervision.SupervisionManagerInternal;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.Context;
 import android.content.Intent;
@@ -488,6 +489,11 @@
         public Context createContextAsUser(UserHandle user) {
             return context;
         }
+
+        @Override
+        SupervisionManagerInternal getSupervisionManager() {
+            return services.supervisionManagerInternal;
+        }
     }
 
     static class TransferOwnershipMetadataManagerMockInjector extends
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index cb4269a..cf5dc4b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -109,6 +109,7 @@
 import android.app.admin.PreferentialNetworkServiceConfig;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.WifiSsidPolicy;
+import android.app.admin.flags.Flags;
 import android.app.role.RoleManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -134,6 +135,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.security.KeyChain;
@@ -165,6 +170,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.mockito.internal.util.collections.Sets;
@@ -207,6 +213,9 @@
     public static final String INVALID_CALLING_IDENTITY_MSG = "Calling identity is not authorized";
     public static final String ONGOING_CALL_MSG = "ongoing call on the device";
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     // TODO replace all instances of this with explicit {@link #mServiceContext}.
     @Deprecated
     private DpmMockContext mContext;
@@ -4425,6 +4434,7 @@
     }
 
     @Test
+    @Ignore("b/359188869")
     public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
@@ -4902,6 +4912,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_profileOwner() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4930,6 +4941,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_deviceOwner() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
 
@@ -4948,6 +4960,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_nonOwner() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4964,6 +4977,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4996,6 +5010,51 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
+    public void testIsSecondaryLockscreenEnabled() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        verifyIsSecondaryLockscreenEnabled(false);
+        verifyIsSecondaryLockscreenEnabled(true);
+    }
+
+    private void verifyIsSecondaryLockscreenEnabled(boolean expected) throws Exception {
+        reset(getServices().supervisionManagerInternal);
+
+        doReturn(expected).when(getServices().supervisionManagerInternal)
+                .isSupervisionLockscreenEnabledForUser(anyInt());
+
+        final boolean enabled = dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE));
+        verify(getServices().supervisionManagerInternal)
+                .isSupervisionLockscreenEnabledForUser(CALLER_USER_HANDLE);
+
+        assertThat(enabled).isEqualTo(expected);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
+    public void testSetSecondaryLockscreenEnabled() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        verifySetSecondaryLockscreenEnabled(false);
+        verifySetSecondaryLockscreenEnabled(true);
+    }
+
+    private void verifySetSecondaryLockscreenEnabled(boolean enabled) throws Exception {
+        reset(getServices().supervisionManagerInternal);
+
+        dpm.setSecondaryLockscreenEnabled(admin1, enabled);
+        verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser(
+                CALLER_USER_HANDLE, enabled, null);
+
+        reset(getServices().supervisionManagerInternal);
+
+        dpm.setSecondaryLockscreenEnabled(enabled, new PersistableBundle());
+        verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser(
+                eq(CALLER_USER_HANDLE), eq(enabled), any(PersistableBundle.class));
+    }
+
+    @Test
     public void testIsDeviceManaged() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 2e200a9..3e4448c1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -35,6 +35,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.IBackupManager;
 import android.app.role.RoleManager;
+import android.app.supervision.SupervisionManagerInternal;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -77,8 +78,8 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.AlarmManagerInternal;
-import com.android.server.pdb.PersistentDataBlockManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.pdb.PersistentDataBlockManagerInternal;
 import com.android.server.pm.PackageManagerLocal;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.pkg.PackageState;
@@ -149,6 +150,7 @@
     public final BuildMock buildMock = new BuildMock();
     public final File dataDir;
     public final PolicyPathProvider pathProvider;
+    public final SupervisionManagerInternal supervisionManagerInternal;
 
     private final Map<String, PackageState> mTestPackageStates = new ArrayMap<>();
 
@@ -203,6 +205,7 @@
         roleManager = realContext.getSystemService(RoleManager.class);
         roleManagerForMock = mock(RoleManagerForMock.class);
         subscriptionManager = mock(SubscriptionManager.class);
+        supervisionManagerInternal = mock(SupervisionManagerInternal.class);
 
         // Package manager is huge, so we use a partial mock instead.
         packageManager = spy(realContext.getPackageManager());
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 73aec63..510c2bc 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -532,6 +532,8 @@
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
         projection.start(mIMediaProjectionCallback);
 
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, projection.packageName);
         doReturn(true).when(mKeyguardManager).isKeyguardLocked();
         MediaProjectionManagerService.BinderService mediaProjectionBinderService =
                 mService.new BinderService(mContext);
@@ -540,50 +542,6 @@
         verify(mContext, never()).startActivityAsUser(any(), any());
     }
 
-    @EnableFlags(android.companion.virtualdevice.flags
-            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
-    @Test
-    public void testKeyguardLocked_stopsActiveProjection() throws Exception {
-        MediaProjectionManagerService service =
-                new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
-        MediaProjectionManagerService.MediaProjection projection =
-                startProjectionPreconditions(service);
-        projection.start(mIMediaProjectionCallback);
-        projection.notifyVirtualDisplayCreated(10);
-
-        assertThat(service.getActiveProjectionInfo()).isNotNull();
-
-        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager)
-                .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName);
-        service.onKeyguardLockedStateChanged(true);
-
-        verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN);
-        assertThat(service.getActiveProjectionInfo()).isNull();
-        assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue();
-    }
-
-    @EnableFlags(android.companion.virtualdevice.flags
-            .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
-    @Test
-    public void testKeyguardLocked_packageAllowlisted_doesNotStopActiveProjection()
-            throws NameNotFoundException {
-        MediaProjectionManagerService service =
-                new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
-        MediaProjectionManagerService.MediaProjection projection =
-                startProjectionPreconditions(service);
-        projection.start(mIMediaProjectionCallback);
-        projection.notifyVirtualDisplayCreated(10);
-
-        assertThat(service.getActiveProjectionInfo()).isNotNull();
-
-        doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
-                RECORD_SENSITIVE_CONTENT, projection.packageName);
-        service.onKeyguardLockedStateChanged(true);
-
-        verifyZeroInteractions(mMediaProjectionMetricsLogger);
-        assertThat(service.getActiveProjectionInfo()).isNotNull();
-    }
-
     @Test
     public void stop_noActiveProjections_doesNotLog() throws Exception {
         MediaProjectionManagerService service =
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java
new file mode 100644
index 0000000..affcfc1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java
@@ -0,0 +1,468 @@
+/*
+ * 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.server.media.projection;
+
+
+import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT;
+import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.Instrumentation;
+import android.app.KeyguardManager;
+import android.app.role.RoleManager;
+import android.companion.AssociationRequest;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.projection.MediaProjectionManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.testing.TestableContext;
+import android.util.ArraySet;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests for the {@link MediaProjectionStopController} class.
+ * <p>
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:MediaProjectionStopControllerTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"})
+public class MediaProjectionStopControllerTest {
+    private static final int UID = 10;
+    private static final String PACKAGE_NAME = "test.package";
+    private final ApplicationInfo mAppInfo = new ApplicationInfo();
+    @Rule
+    public final TestableContext mContext = spy(
+            new TestableContext(InstrumentationRegistry.getInstrumentation().getContext()));
+
+    private final MediaProjectionManagerService.Injector mMediaProjectionMetricsLoggerInjector =
+            new MediaProjectionManagerService.Injector() {
+                @Override
+                MediaProjectionMetricsLogger mediaProjectionMetricsLogger(Context context) {
+                    return mMediaProjectionMetricsLogger;
+                }
+            };
+
+    private MediaProjectionManagerService mService;
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Mock
+    private ActivityManagerInternal mAmInternal;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private KeyguardManager mKeyguardManager;
+    @Mock
+    private TelecomManager mTelecomManager;
+
+    private AppOpsManager mAppOpsManager;
+    @Mock
+    private MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
+    @Mock
+    private Consumer<Integer> mStopConsumer;
+
+    private MediaProjectionStopController mStopController;
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class, mAmInternal);
+
+        mAppOpsManager = mockAppOpsManager();
+        mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
+        mContext.addMockSystemService(KeyguardManager.class, mKeyguardManager);
+        mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
+        mContext.setMockPackageManager(mPackageManager);
+
+        mStopController = new MediaProjectionStopController(mContext, mStopConsumer);
+        mService = new MediaProjectionManagerService(mContext,
+                mMediaProjectionMetricsLoggerInjector);
+
+        mAppInfo.targetSdkVersion = 35;
+    }
+
+    private static AppOpsManager mockAppOpsManager() {
+        return mock(AppOpsManager.class, invocationOnMock -> {
+            if (invocationOnMock.getMethod().getName().startsWith("noteOp")) {
+                // Mockito will return 0 for non-stubbed method which corresponds to MODE_ALLOWED
+                // and is not what we want.
+                return AppOpsManager.MODE_IGNORED;
+            }
+            return Answers.RETURNS_DEFAULTS.answer(invocationOnMock);
+        });
+    }
+
+    @After
+    public void tearDown() {
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+    }
+
+    @Test
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+    public void testMediaProjectionNotRestricted() throws Exception {
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
+
+        assertThat(mStopController.isStartForbidden(
+                createMediaProjection(PACKAGE_NAME))).isFalse();
+    }
+
+    @Test
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+    public void testMediaProjectionRestricted() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        mediaProjection.notifyVirtualDisplayCreated(1);
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
+
+        assertThat(mStopController.isStartForbidden(mediaProjection)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingNullProjection() throws Exception {
+        assertThat(mStopController.isExemptFromStopping(null,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingInvalidProjection() throws Exception {
+        assertThat(mStopController.isExemptFromStopping(createMediaProjection(null),
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingDisableScreenshareProtections() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        int value = Settings.Global.getInt(mContext.getContentResolver(),
+                DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0);
+        try {
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1);
+
+            assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                    MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+        } finally {
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, value);
+        }
+    }
+
+    @Test
+    public void testExemptFromStoppingHasOpProjectMedia() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager)
+                .noteOpNoThrow(eq(AppOpsManager.OP_PROJECT_MEDIA),
+                        eq(mediaProjection.uid), eq(mediaProjection.packageName),
+                        nullable(String.class),
+                        nullable(String.class));
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingHasAppStreamingRole() throws Exception {
+        runWithRole(
+                AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
+                () -> {
+                    try {
+                        MediaProjectionManagerService.MediaProjection mediaProjection =
+                                createMediaProjection();
+                        doReturn(PackageManager.PERMISSION_DENIED).when(
+                                mPackageManager).checkPermission(
+                                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+                        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+    }
+
+    @Test
+    public void testExemptFromStoppingIsBugreportAllowlisted() throws Exception {
+        ArraySet<String> packages = SystemConfig.getInstance().getBugreportWhitelistedPackages();
+        if (packages.isEmpty()) {
+            return;
+        }
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(
+                packages.valueAt(0));
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingHasNoDisplay() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(
+                PACKAGE_NAME);
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingHasRecordSensitiveContentPermission() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
+    }
+
+    @Test
+    public void testExemptFromStoppingIsFalse() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        mediaProjection.notifyVirtualDisplayCreated(1);
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+    public void testKeyguardLockedStateChanged_unlocked() {
+        mStopController.onKeyguardLockedStateChanged(false);
+
+        verify(mStopConsumer, never()).accept(anyInt());
+    }
+
+    @Test
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+    public void testKeyguardLockedStateChanged_locked() {
+        mStopController.onKeyguardLockedStateChanged(true);
+
+        verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_KEYGUARD);
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testCallStateChanged_callStarts() {
+        // Setup call state to false
+        when(mTelecomManager.isInCall()).thenReturn(false);
+        mStopController.callStateChanged();
+
+        clearInvocations(mStopConsumer);
+
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        verify(mStopConsumer, never()).accept(anyInt());
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testCallStateChanged_remainsInCall() {
+        // Setup call state to false
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        clearInvocations(mStopConsumer);
+
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        verify(mStopConsumer, never()).accept(anyInt());
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testCallStateChanged_remainsNoCall() {
+        // Setup call state to false
+        when(mTelecomManager.isInCall()).thenReturn(false);
+        mStopController.callStateChanged();
+
+        clearInvocations(mStopConsumer);
+
+        when(mTelecomManager.isInCall()).thenReturn(false);
+        mStopController.callStateChanged();
+
+        verify(mStopConsumer, never()).accept(anyInt());
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testCallStateChanged_callEnds() {
+        // Setup call state to false
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        clearInvocations(mStopConsumer);
+
+        when(mTelecomManager.isInCall()).thenReturn(false);
+        mStopController.callStateChanged();
+
+        verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_CALL_END);
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testExemptFromStopping_callEnd_callBeforeMediaProjection() throws Exception {
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        mediaProjection.notifyVirtualDisplayCreated(1);
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_CALL_END)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
+    public void testExemptFromStopping_callEnd_callAfterMediaProjection() throws Exception {
+        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
+        mediaProjection.notifyVirtualDisplayCreated(1);
+        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
+
+        when(mTelecomManager.isInCall()).thenReturn(true);
+        mStopController.callStateChanged();
+
+        assertThat(mStopController.isExemptFromStopping(mediaProjection,
+                MediaProjectionStopController.STOP_REASON_CALL_END)).isTrue();
+    }
+
+    private MediaProjectionManagerService.MediaProjection createMediaProjection()
+            throws NameNotFoundException {
+        return createMediaProjection(PACKAGE_NAME);
+    }
+
+    private MediaProjectionManagerService.MediaProjection createMediaProjection(String packageName)
+            throws NameNotFoundException {
+        doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(),
+                any(ApplicationInfoFlags.class), any(UserHandle.class));
+        doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(Mockito.isNull(),
+                any(ApplicationInfoFlags.class), any(UserHandle.class));
+        return mService.createProjectionInternal(UID, packageName,
+                MediaProjectionManager.TYPE_SCREEN_CAPTURE, false, mContext.getUser(),
+                INVALID_DISPLAY);
+    }
+
+    /**
+     * Run the provided block giving the current context's package the provided role.
+     */
+    @SuppressWarnings("SameParameterValue")
+    private void runWithRole(String role, Runnable block) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        String packageName = mContext.getPackageName();
+        UserHandle user = instrumentation.getTargetContext().getUser();
+        RoleManager roleManager = Objects.requireNonNull(
+                mContext.getSystemService(RoleManager.class));
+        try {
+            CountDownLatch latch = new CountDownLatch(1);
+            instrumentation.getUiAutomation().adoptShellPermissionIdentity(
+                    Manifest.permission.MANAGE_ROLE_HOLDERS,
+                    Manifest.permission.BYPASS_ROLE_QUALIFICATION);
+
+            roleManager.setBypassingRoleQualification(true);
+            roleManager.addRoleHolderAsUser(role, packageName,
+                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
+                    mContext.getMainExecutor(), success -> {
+                        if (success) {
+                            latch.countDown();
+                        } else {
+                            Assert.fail("Couldn't set role for test (failure) " + role);
+                        }
+                    });
+            assertWithMessage("Couldn't set role for test (timeout) : " + role)
+                    .that(latch.await(1, TimeUnit.SECONDS)).isTrue();
+            block.run();
+
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } finally {
+            roleManager.removeRoleHolderAsUser(role, packageName,
+                    /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user,
+                    mContext.getMainExecutor(), (aBool) -> {
+                    });
+            roleManager.setBypassingRoleQualification(false);
+            instrumentation.getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS b/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS
deleted file mode 100644
index bc8efa9..0000000
--- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java
rename to services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
index 154494a..2238a1b 100644
--- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.server.security.adaptiveauthentication;
+package com.android.server.security.authenticationpolicy;
 
 import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH;
 import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS;
 import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
-import static com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
+import static com.android.server.security.authenticationpolicy.AuthenticationPolicyService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
@@ -66,12 +66,12 @@
 import org.mockito.MockitoAnnotations;
 
 /**
- * atest FrameworksServicesTests:AdaptiveAuthenticationServiceTest
+ * atest FrameworksServicesTests:AuthenticationPolicyServiceTest
  */
 @Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class AdaptiveAuthenticationServiceTest {
+public class AuthenticationPolicyServiceTest {
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -81,7 +81,7 @@
     private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason
 
     private Context mContext;
-    private AdaptiveAuthenticationService mAdaptiveAuthenticationService;
+    private AuthenticationPolicyService mAuthenticationPolicyService;
 
     @Mock
     LockPatternUtils mLockPatternUtils;
@@ -124,9 +124,9 @@
         LocalServices.removeServiceForTest(UserManagerInternal.class);
         LocalServices.addService(UserManagerInternal.class, mUserManager);
 
-        mAdaptiveAuthenticationService = new AdaptiveAuthenticationService(
+        mAuthenticationPolicyService = new AuthenticationPolicyService(
                 mContext, mLockPatternUtils);
-        mAdaptiveAuthenticationService.init();
+        mAuthenticationPolicyService.init();
 
         verify(mLockSettings).registerLockSettingsStateListener(
                 mLockSettingsStateListenerCaptor.capture());
@@ -318,13 +318,13 @@
 
     private void verifyNotLockDevice(int expectedCntFailedAttempts, int userId) {
         assertEquals(expectedCntFailedAttempts,
-                mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId));
+                mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId));
         verify(mWindowManager, never()).lockNow();
     }
 
     private void verifyLockDevice(int userId) {
         assertEquals(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS,
-                mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId));
+                mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId));
         verify(mLockPatternUtils).requireStrongAuth(
                 eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(userId));
         // If userId is MANAGED_PROFILE_USER_ID, the StrongAuthFlag of its parent (PRIMARY_USER_ID)
diff --git a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS
new file mode 100644
index 0000000..4310d1a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
index 79b06236..8290e1c 100644
--- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt
@@ -20,7 +20,7 @@
 import android.content.ComponentName
 import android.content.Context
 import android.content.pm.UserInfo
-import android.os.Bundle
+import android.os.PersistableBundle
 import android.platform.test.annotations.RequiresFlagsEnabled
 import android.platform.test.flag.junit.DeviceFlagsValueProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -139,7 +139,7 @@
         assertThat(userData.supervisionLockScreenEnabled).isFalse()
         assertThat(userData.supervisionLockScreenOptions).isNull()
 
-        service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, Bundle())
+        service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, PersistableBundle())
         userData = service.getUserDataLocked(USER_ID)
         assertThat(userData.supervisionLockScreenEnabled).isTrue()
         assertThat(userData.supervisionLockScreenOptions).isNotNull()
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index cc02865..6af6542 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -84,7 +84,9 @@
 import com.android.internal.R;
 import com.android.server.UiServiceTestCase;
 import com.android.server.notification.GroupHelper.CachedSummary;
+import com.android.server.notification.GroupHelper.FullyQualifiedGroupKey;
 import com.android.server.notification.GroupHelper.NotificationAttributes;
+import com.android.server.notification.GroupHelper.NotificationSectioner;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -2298,6 +2300,7 @@
         final String pkg = "package";
         final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg,
                 AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+        final int numNotifications = 2 * AUTOGROUP_AT_COUNT;
         int numNotificationChannel1 = 0;
         final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1",
                 "TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT);
@@ -2307,7 +2310,7 @@
         final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
         // Post notifications with different channels that autogroup within the same section
         NotificationRecord r;
-        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
+        for (int i = 0; i < numNotifications; i++) {
             if (i % 2 == 0) {
                 r = getNotificationRecord(pkg, i, String.valueOf(i),
                         UserHandle.SYSTEM, "testGrp " + i, false, channel1);
@@ -2324,12 +2327,12 @@
                 "TEST_CHANNEL_ID1");
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
                 eq(expectedGroupKey_alerting), anyInt(), eq(expectedSummaryAttr));
-        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+        verify(mCallback, times(numNotifications)).addAutoGroup(anyString(),
                 eq(expectedGroupKey_alerting), eq(true));
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
-        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
-                any());
+        verify(mCallback, times(numNotifications - AUTOGROUP_AT_COUNT)).updateAutogroupSummary(
+                anyInt(), anyString(), anyString(), any());
         Mockito.reset(mCallback);
 
         // Update channel1's importance
@@ -2375,7 +2378,7 @@
         final List<NotificationRecord> notificationList = new ArrayList<>();
         final String pkg = "package";
         final int summaryId = 0;
-        final int numChildNotif = 4;
+        final int numChildNotif = 2 * AUTOGROUP_AT_COUNT;
 
         // Create an app-provided group: summary + child notifications
         final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1",
@@ -2435,8 +2438,8 @@
                 eq(expectedGroupKey_social), eq(true));
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
-        verify(mCallback, times(numChildNotif / 2)).updateAutogroupSummary(anyInt(), anyString(),
-                anyString(), any());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
         verify(mCallback, times(numChildNotif)).removeAppProvidedSummaryOnClassification(
                 anyString(), eq(originalAppGroupKey));
     }
@@ -2513,9 +2516,10 @@
         final List<NotificationRecord> notificationList = new ArrayList<>();
         final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
         final String pkg = "package";
+        final int numChildNotifications = AUTOGROUP_AT_COUNT;
 
         // Post singleton groups, above forced group limit
-        for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) {
+        for (int i = 0; i < numChildNotifications; i++) {
             NotificationRecord summary = getNotificationRecord(pkg, i,
                     String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
             notificationList.add(summary);
@@ -2545,13 +2549,13 @@
         // Check that notifications are forced grouped and app-provided summaries are canceled
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
                 eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
-        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+        verify(mCallback, times(numChildNotifications)).addAutoGroup(anyString(),
                 eq(expectedGroupKey_social), eq(true));
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
-        verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
                 any());
-        verify(mCallback, times(2)).removeAppProvidedSummaryOnClassification(
+        verify(mCallback, times(numChildNotifications)).removeAppProvidedSummaryOnClassification(
                 anyString(), anyString());
 
         // Adjust group key and cancel summaries
@@ -2593,14 +2597,16 @@
                 AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
         String expectedTriggeringKey = null;
         // Post singleton groups, above forced group limit
-        for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) {
+        for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) {
             NotificationRecord summary = getNotificationRecord(pkg, i,
                     String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
             notificationList.add(summary);
             NotificationRecord child = getNotificationRecord(pkg, i + 42,
                     String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false);
             notificationList.add(child);
-            expectedTriggeringKey = child.getKey();
+            if (i == AUTOGROUP_SINGLETONS_AT_COUNT - 1) {
+                expectedTriggeringKey = child.getKey();
+            }
             summaryByGroup.put(summary.getGroupKey(), summary);
             mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
             summary.isCanceled = true;  // simulate removing the app summary
@@ -2611,14 +2617,8 @@
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg),
                 eq(expectedTriggeringKey), eq(expectedGroupKey_alerting), anyInt(),
                 eq(getNotificationAttributes(BASE_FLAGS)));
-        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
-                eq(expectedGroupKey_alerting), eq(true));
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
-        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
-                any());
-        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary(
-                anyString());
         assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(0), 0,
                 UserHandle.SYSTEM.getIdentifier())).isNotNull();
         assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(1), 1,
@@ -2645,12 +2645,12 @@
         // Check that all notifications are moved to the social section group
         verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
                 eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
-        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
                 eq(expectedGroupKey_social), eq(true));
         // Check that the alerting section group is removed
         verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg),
                 eq(expectedGroupKey_alerting));
-        verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).updateAutogroupSummary(anyInt(),
+        verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(),
                 anyString(), anyString(), any());
     }
 
@@ -2666,7 +2666,7 @@
         final String pkg = "package";
 
         final int summaryId = 0;
-        final int numChildren = 3;
+        final int numChildren = AUTOGROUP_AT_COUNT;
         // Post a regular/valid group: summary + notifications
         NotificationRecord summary = getNotificationRecord(pkg, summaryId,
                 String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
@@ -2706,13 +2706,211 @@
                 eq(true));
         verify(mCallback, never()).removeAutoGroup(anyString());
         verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
-        verify(mCallback, times(numChildren - 1)).updateAutogroupSummary(anyInt(), anyString(),
-                anyString(), any());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
         verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(anyString(),
                 anyString());
     }
 
     @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+            FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
+            FLAG_NOTIFICATION_CLASSIFICATION})
+    public void testUnbundleNotification_originalSummaryMissing_autogroupInNewSection() {
+        // Check that unbundled notifications are moved to the original section and aggregated
+        // with existing autogrouped notifications
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+
+        final int summaryId = 0;
+        final int numChildren = AUTOGROUP_AT_COUNT - 1;
+        // Post a regular/valid group: summary + notifications (one less than autogroup limit)
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+                String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        final String originalAppGroupKey = summary.getGroupKey();
+        final NotificationChannel originalChannel = summary.getChannel();
+        for (int i = 0; i < numChildren; i++) {
+            NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+                    UserHandle.SYSTEM, "testGrp", false);
+            notificationList.add(child);
+            mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+        }
+
+        // Classify/bundle all child notifications: original group & summary is removed
+        final NotificationChannel socialChannel = new NotificationChannel(
+                NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+                IMPORTANCE_DEFAULT);
+        for (NotificationRecord record: notificationList) {
+            if (record.getOriginalGroupKey().contains("testGrp")
+                    && record.getNotification().isGroupChild()) {
+                record.updateNotificationChannel(socialChannel);
+                mGroupHelper.onChannelUpdated(record);
+            }
+        }
+
+        // Check that no autogroup summaries were created for the social section
+        verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(),
+                anyString(), anyInt(), any());
+        verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
+        verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(
+                anyString(), eq(originalAppGroupKey));
+
+        // Cancel summary
+        summary.isCanceled = true;
+        summaryByGroup.clear();
+        notificationList.remove(summary);
+
+        // Add 1 ungrouped notification in the original section
+        NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242,
+                String.valueOf(4242), UserHandle.SYSTEM);
+        notificationList.add(ungroupedNotification);
+        mGroupHelper.onNotificationPosted(ungroupedNotification, false);
+
+        // Unbundle the bundled notifications => notifications are moved back to the original group
+        // and an aggregate group is created because autogroup limit is reached
+        reset(mCallback);
+        for (NotificationRecord record: notificationList) {
+            if (record.getNotification().isGroupChild()
+                    && record.getOriginalGroupKey().contains("testGrp")
+                    && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+                        record.getChannel().getId())) {
+                record.updateNotificationChannel(originalChannel);
+                mGroupHelper.onNotificationUnbundled(record, false);
+            }
+        }
+
+        // Check that a new aggregate group is created
+        final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg,
+                AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+                eq(expectedGroupKey_alerting), anyInt(), any());
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+                eq(expectedGroupKey_alerting), eq(true));
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, times(numChildren)).removeAutoGroupSummary(anyInt(), anyString(),
+                anyString());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
+    }
+
+    @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+            FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION,
+            FLAG_NOTIFICATION_CLASSIFICATION})
+    public void testUnbundleNotification_originalSummaryExists() {
+        // Check that unbundled notifications are moved to the original section and original group
+        // when the original summary is still present
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+
+        final int summaryId = 0;
+        final int numChildren = AUTOGROUP_AT_COUNT + 1;
+        // Post a regular/valid group: summary + notifications
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId,
+                String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        final String originalAppGroupKey = summary.getGroupKey();
+        final NotificationChannel originalChannel = summary.getChannel();
+        for (int i = 0; i < numChildren; i++) {
+            NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42),
+                    UserHandle.SYSTEM, "testGrp", false);
+            notificationList.add(child);
+            mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+        }
+
+        // Classify/bundle child notifications: all except one, to keep the original group
+        final NotificationChannel socialChannel = new NotificationChannel(
+                NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID,
+                IMPORTANCE_DEFAULT);
+        final String expectedGroupKey_social = GroupHelper.getFullAggregateGroupKey(pkg,
+                AGGREGATE_GROUP_KEY + "SocialSection", UserHandle.SYSTEM.getIdentifier());
+        final NotificationAttributes expectedSummaryAttr_social = new NotificationAttributes(
+                BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT,
+                NotificationChannel.SOCIAL_MEDIA_ID);
+        int numChildrenBundled = 0;
+        for (NotificationRecord record: notificationList) {
+            if (record.getOriginalGroupKey().contains("testGrp")
+                    && record.getNotification().isGroupChild()) {
+                record.updateNotificationChannel(socialChannel);
+                mGroupHelper.onChannelUpdated(record);
+                numChildrenBundled++;
+                if (numChildrenBundled == AUTOGROUP_AT_COUNT) {
+                    break;
+                }
+            }
+        }
+
+        // Check that 1 autogroup summaries were created for the social section
+        verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
+                eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(),
+                eq(expectedGroupKey_social), eq(true));
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+        verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+                any());
+        verify(mCallback, times(AUTOGROUP_AT_COUNT)).removeAppProvidedSummaryOnClassification(
+                anyString(), eq(originalAppGroupKey));
+
+        // Adjust group key and cancel summaries
+        for (NotificationRecord record: notificationList) {
+            if (record.getNotification().isGroupSummary()) {
+                record.isCanceled = true;
+            } else if (record.getOriginalGroupKey().contains("testGrp")
+                        && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+                        record.getChannel().getId())) {
+                record.setOverrideGroupKey(expectedGroupKey_social);
+            }
+        }
+
+        // Add 1 ungrouped notification in the original section
+        NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242,
+                String.valueOf(4242), UserHandle.SYSTEM);
+        notificationList.add(ungroupedNotification);
+        mGroupHelper.onNotificationPosted(ungroupedNotification, false);
+
+        // Unbundle the bundled notifications => social section summary is destroyed
+        // and notifications are moved back to the original group
+        reset(mCallback);
+        for (NotificationRecord record: notificationList) {
+            if (record.getNotification().isGroupChild()
+                    && record.getOriginalGroupKey().contains("testGrp")
+                    && NotificationChannel.SYSTEM_RESERVED_IDS.contains(
+                        record.getChannel().getId())) {
+                record.updateNotificationChannel(originalChannel);
+                mGroupHelper.onNotificationUnbundled(record, true);
+            }
+        }
+
+        // Check that the autogroup summary for the social section was removed
+        // and that no new autogroup summaries were created
+        verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(),
+                anyString(), anyInt(), any());
+        verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean());
+        verify(mCallback, never()).removeAutoGroup(anyString());
+        verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg),
+                eq(expectedGroupKey_social));
+        verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(), eq(pkg),
+                eq(expectedGroupKey_social), any());
+
+        for (NotificationRecord record: notificationList) {
+            if (record.getNotification().isGroupChild()
+                    && record.getOriginalGroupKey().contains("testGrp")) {
+                assertThat(record.getSbn().getOverrideGroupKey()).isNull();
+            }
+        }
+    }
+
+    @Test
     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
     public void testMoveAggregateGroups_updateChannel_groupsUngrouped() {
         final String pkg = "package";
@@ -3059,6 +3257,120 @@
     @Test
     @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
     @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS)
+    public void testNonGroupableChildren_singletonGroups_disableConversations() {
+        // Check that singleton groups with children that are not groupable, is not grouped
+        // Even though the group summary is a regular (alerting) notification, the children are
+        // conversations => the group should not be forced grouped.
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+
+        // Trigger notification, ungrouped
+        final int triggerId = 1;
+        NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId,
+                String.valueOf(triggerId), UserHandle.SYSTEM);
+        notificationList.add(triggerNotification);
+        final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification);
+        final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey(
+                triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(),
+                triggerSection);
+
+        // Add singleton group with alerting child
+        final String groupName_valid = "testGrp_valid";
+        final int summaryId_valid = 0;
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid,
+                String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        final String groupKey_valid = summary.getGroupKey();
+        NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42,
+                String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false);
+        notificationList.add(child);
+
+        // Add singleton group with conversation child
+        final String groupName_invalid = "testGrp_invalid";
+        final int summaryId_invalid = 100;
+        summary = getNotificationRecord(pkg, summaryId_invalid,
+                String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true);
+        notificationList.add(summary);
+        final String groupKey_invalid = summary.getGroupKey();
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        child = getNotificationRecord(pkg, summaryId_invalid + 42,
+                String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid,
+                false);
+        child = spy(child);
+        when(child.isConversation()).thenReturn(true);
+        notificationList.add(child);
+
+        // Check that the invalid group will not be force grouped
+        final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups(
+                triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection);
+        assertThat(sparseGroups).containsKey(groupKey_valid);
+        assertThat(sparseGroups).doesNotContainKey(groupKey_invalid);
+    }
+
+    @Test
+    @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS})
+    public void testNonGroupableChildren_singletonGroups_enableConversations() {
+        // Check that singleton groups with children that are not groupable, is not grouped
+        // Conversations are groupable (FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS is enabled)
+        // The invalid group is the alerting notifications: because the triggering notifications'
+        // section is Conversations, so the alerting group should be skipped.
+        final List<NotificationRecord> notificationList = new ArrayList<>();
+        final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+        final String pkg = "package";
+
+        // Trigger notification, ungrouped conversation
+        final int triggerId = 1;
+        NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId,
+                String.valueOf(triggerId), UserHandle.SYSTEM);
+        triggerNotification = spy(triggerNotification);
+        when(triggerNotification.isConversation()).thenReturn(true);
+        notificationList.add(triggerNotification);
+        final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification);
+        final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey(
+                triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(),
+                triggerSection);
+
+        // Add singleton group with conversation child
+        final String groupName_valid = "testGrp_valid";
+        final int summaryId_valid = 0;
+        NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid,
+                String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true);
+        summary = spy(summary);
+        when(summary.isConversation()).thenReturn(true);
+        notificationList.add(summary);
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        final String groupKey_valid = summary.getGroupKey();
+        NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42,
+                String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false);
+        child = spy(child);
+        when(child.isConversation()).thenReturn(true);
+        notificationList.add(child);
+
+        // Add singleton group with non-conversation child
+        final String groupName_invalid = "testGrp_invalid";
+        final int summaryId_invalid = 100;
+        summary = getNotificationRecord(pkg, summaryId_invalid,
+                String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true);
+        notificationList.add(summary);
+        final String groupKey_invalid = summary.getGroupKey();
+        summaryByGroup.put(summary.getGroupKey(), summary);
+        child = getNotificationRecord(pkg, summaryId_invalid + 42,
+                String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid,
+                false);
+        notificationList.add(child);
+
+        // Check that the invalid group will not be force grouped
+        final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups(
+                triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection);
+        assertThat(sparseGroups).containsKey(groupKey_valid);
+        assertThat(sparseGroups).doesNotContainKey(groupKey_invalid);
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING)
+    @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS)
     public void testNonGroupableNotifications() {
         // Check that there is no valid section for: conversations, calls, foreground services
         NotificationRecord notification_conversation = mock(NotificationRecord.class);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 6eb2f71..9eddcc9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -720,6 +720,7 @@
     }
 
     @Test
+    @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
     public void testDefaultAllowedKeyAdjustments_readWriteXml() throws Exception {
         mAssistants.loadDefaultsFromConfig(true);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index eae587b..704c1b8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -210,6 +210,7 @@
 import android.app.RemoteInput;
 import android.app.RemoteInputHistoryItem;
 import android.app.StatsManager;
+import android.app.ZenBypassingApp;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.backup.BackupRestoreEventLogger;
 import android.app.job.JobScheduler;
@@ -360,6 +361,9 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -374,9 +378,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
 @SmallTest
 @RunWith(ParameterizedAndroidJunit4.class)
 @RunWithLooper
@@ -489,7 +490,8 @@
     private final NotificationChannel mParentChannel =
             new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT);
     private final NotificationChannel mConversationChannel =
-            new NotificationChannel(CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
+            new NotificationChannel(
+                    CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT);
 
     private static final String PARENT_CHANNEL_ID = "parentChannelId";
     private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId";
@@ -4296,8 +4298,13 @@
                     new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
 
         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
-        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_onTv", 0,
-                generateNotificationRecord(null, tv).getNotification(), mUserId);
+        mBinderService.enqueueNotificationWithTag(
+                mPkg,
+                mPkg,
+                "testTvExtenderChannelOverride_onTv",
+                0,
+                generateNotificationRecord(null, tv).getNotification(),
+                mUserId);
         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
                 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean());
     }
@@ -4311,8 +4318,13 @@
                 mTestNotificationChannel);
 
         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
-        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_notOnTv",
-                0, generateNotificationRecord(null, tv).getNotification(), mUserId);
+        mBinderService.enqueueNotificationWithTag(
+                mPkg,
+                mPkg,
+                "testTvExtenderChannelOverride_notOnTv",
+                0,
+                generateNotificationRecord(null, tv).getNotification(),
+                mUserId);
         verify(mPreferencesHelper, times(1)).getConversationNotificationChannel(
                 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null),
                 anyBoolean(), anyBoolean());
@@ -7745,9 +7757,21 @@
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setStyle(new Notification.MessagingStyle("").addMessage(message2));
-        NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(mPkg,
-                mPkg, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0),
-                c);
+        NotificationRecord recordB =
+                new NotificationRecord(
+                        mContext,
+                        new StatusBarNotification(
+                                mPkg,
+                                mPkg,
+                                0,
+                                "tag",
+                                mUid,
+                                0,
+                                nbB.build(),
+                                UserHandle.getUserHandleForUid(mUid),
+                                null,
+                                0),
+                        c);
 
         // Update means we drop access to first
         reset(mUgmInternal);
@@ -13174,6 +13198,37 @@
     }
 
     @Test
+    public void getPackagesBypassingDnd_blocked()
+            throws RemoteException, PackageManager.NameNotFoundException {
+
+        NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+                NotificationManager.IMPORTANCE_MAX);
+        NotificationChannel channel2 = new NotificationChannel("id3", "name3",
+                NotificationManager.IMPORTANCE_MAX);
+        NotificationChannel channel3 = new NotificationChannel("id4", "name3",
+                NotificationManager.IMPORTANCE_MAX);
+        channel1.setBypassDnd(true);
+        channel2.setBypassDnd(true);
+        channel3.setBypassDnd(false);
+        // has DND access, so can set bypassDnd attribute
+        mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+                /*has DND access*/ true, UID_N_MR1, false);
+        mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true,
+                UID_P, false);
+        mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
+                UID_P, false);
+
+        when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P);
+        when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt()))
+                .thenReturn(UID_N_MR1);
+        when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false);
+        when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true);
+
+        assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList())
+                .containsExactly(new ZenBypassingApp(PKG_P, false));
+    }
+
+    @Test
     public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
         mService.setPreferencesHelper(mPreferencesHelper);
 
@@ -13187,125 +13242,11 @@
     @Test
     public void testGetPackagesBypassingDnd_empty() throws RemoteException {
         mService.setPreferencesHelper(mPreferencesHelper);
-        List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
+        List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList();
         assertThat(result).isEmpty();
     }
 
     @Test
-    public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException {
-        mService.setPreferencesHelper(mPreferencesHelper);
-
-        // Set packages
-        PackageInfo pkg0 = new PackageInfo();
-        pkg0.packageName = "pkg0";
-        pkg0.applicationInfo = new ApplicationInfo();
-        pkg0.applicationInfo.uid = mUid;
-        PackageInfo pkg1 = new PackageInfo();
-        pkg1.packageName = "pkg1";
-        pkg1.applicationInfo = new ApplicationInfo();
-        pkg1.applicationInfo.uid = mUid;
-        PackageInfo pkg2 = new PackageInfo();
-        pkg2.packageName = "pkg2";
-        pkg2.applicationInfo = new ApplicationInfo();
-        pkg2.applicationInfo.uid = mUid;
-
-        when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
-                .thenReturn(List.of(pkg0, pkg1, pkg2));
-
-        // Conversation channels
-        NotificationChannel nc0 = new NotificationChannel("id0", "id0",
-                NotificationManager.IMPORTANCE_HIGH);
-        nc0.setConversationId("parentChannel", "conversationId");
-
-        // Demoted conversation channel
-        NotificationChannel nc1 = new NotificationChannel("id1", "id1",
-                NotificationManager.IMPORTANCE_HIGH);
-        nc1.setConversationId("parentChannel", "conversationId");
-        nc1.setDemoted(true);
-
-        // Non-conversation channels
-        NotificationChannel nc2 = new NotificationChannel("id2", "id2",
-                NotificationManager.IMPORTANCE_HIGH);
-        NotificationChannel nc3 = new NotificationChannel("id3", "id3",
-                NotificationManager.IMPORTANCE_HIGH);
-
-        ParceledListSlice<NotificationChannel> pls0 =
-                new ParceledListSlice(ImmutableList.of(nc0));
-        ParceledListSlice<NotificationChannel> pls1 =
-                new ParceledListSlice(ImmutableList.of(nc1));
-        ParceledListSlice<NotificationChannel> pls2 =
-                new ParceledListSlice(ImmutableList.of(nc2, nc3));
-
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
-                .thenReturn(pls0);
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
-                .thenReturn(pls1);
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
-                .thenReturn(pls2);
-
-        List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false);
-
-        assertThat(result).containsExactly("pkg1", "pkg2");
-    }
-
-    @Test
-    public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException {
-        mService.setPreferencesHelper(mPreferencesHelper);
-
-        // Set packages
-        PackageInfo pkg0 = new PackageInfo();
-        pkg0.packageName = "pkg0";
-        pkg0.applicationInfo = new ApplicationInfo();
-        pkg0.applicationInfo.uid = mUid;
-        PackageInfo pkg1 = new PackageInfo();
-        pkg1.packageName = "pkg1";
-        pkg1.applicationInfo = new ApplicationInfo();
-        pkg1.applicationInfo.uid = mUid;
-        PackageInfo pkg2 = new PackageInfo();
-        pkg2.packageName = "pkg2";
-        pkg2.applicationInfo = new ApplicationInfo();
-        pkg2.applicationInfo.uid = mUid;
-
-        when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId))
-                .thenReturn(List.of(pkg0, pkg1, pkg2));
-
-        // Conversation channels
-        NotificationChannel nc0 = new NotificationChannel("id0", "id0",
-                NotificationManager.IMPORTANCE_HIGH);
-        nc0.setConversationId("parentChannel", "conversationId");
-
-        // Demoted conversation channel
-        NotificationChannel nc1 = new NotificationChannel("id1", "id1",
-                NotificationManager.IMPORTANCE_HIGH);
-        nc1.setConversationId("parentChannel", "conversationId");
-        nc1.setDemoted(true);
-
-        // Non-conversation channels
-        NotificationChannel nc2 = new NotificationChannel("id2", "id2",
-                NotificationManager.IMPORTANCE_HIGH);
-        NotificationChannel nc3 = new NotificationChannel("id3", "id3",
-                NotificationManager.IMPORTANCE_HIGH);
-
-        ParceledListSlice<NotificationChannel> pls0 =
-                new ParceledListSlice(ImmutableList.of(nc0));
-        ParceledListSlice<NotificationChannel> pls1 =
-                new ParceledListSlice(ImmutableList.of(nc1));
-        ParceledListSlice<NotificationChannel> pls2 =
-                new ParceledListSlice(ImmutableList.of(nc2, nc3));
-
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid))
-                .thenReturn(pls0);
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid))
-                .thenReturn(pls1);
-        when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid))
-                .thenReturn(pls2);
-
-        List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true);
-
-        assertThat(result).containsExactly("pkg0", "pkg1", "pkg2");
-    }
-
-    @Test
     public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception {
         // set the testable NMS to not system uid/appid
         mService.isSystemUid = false;
@@ -15482,8 +15423,13 @@
         for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
             StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel,
                     i, null, false).getSbn();
-            mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCannotPostNonUijWhenOverLimit",
-                    sbn.getId(), sbn.getNotification(), sbn.getUserId());
+            mBinderService.enqueueNotificationWithTag(
+                    mPkg,
+                    mPkg,
+                    "testCannotPostNonUijWhenOverLimit",
+                    sbn.getId(),
+                    sbn.getNotification(),
+                    sbn.getUserId());
             waitForIdle();
         }
 
@@ -16213,6 +16159,8 @@
         initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
         // No exception!
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index e1b478c..dda060d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -108,6 +108,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.app.NotificationManager;
+import android.app.ZenBypassingApp;
 import android.content.AttributionSource;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -2620,6 +2621,72 @@
     }
 
     @Test
+    public void getPackagesBypassingDnd_noChannelsBypassing() throws Exception {
+        assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
+    }
+
+    @Test
+    public void getPackagesBypassingDnd_oneChannelBypassing_deleted() {
+        NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+                NotificationManager.IMPORTANCE_MAX);
+        channel1.setBypassDnd(true);
+        channel1.setDeleted(true);
+        // has DND access, so can set bypassDnd attribute
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+                /*has DND access*/ true, UID_N_MR1, false);
+
+        assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty();
+    }
+
+    @Test
+    public void getPackagesBypassingDnd_oneChannelBypassing_groupBlocked() {
+        int uid = UID_N_MR1;
+        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+        NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+                NotificationManager.IMPORTANCE_MAX);
+        channel1.setBypassDnd(true);
+        channel1.setGroup(ncg.getId());
+        mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg,  /* fromTargetApp */ true,
+                uid, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true,
+                uid, false);
+        ncg.setBlocked(true);
+
+        assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(uid))).isEmpty();
+    }
+
+    @Test
+    public void getPackagesBypassingDnd_multipleApps() {
+        List<ZenBypassingApp> expected = ImmutableList.of(
+                new ZenBypassingApp(PKG_O, true), new ZenBypassingApp(PKG_P, false));
+
+        NotificationChannel channel1 = new NotificationChannel("id1", "name1",
+                NotificationManager.IMPORTANCE_MAX);
+        NotificationChannel channel2 = new NotificationChannel("id2", "name2",
+                NotificationManager.IMPORTANCE_MAX);
+        NotificationChannel channel3 = new NotificationChannel("id3", "name3",
+                NotificationManager.IMPORTANCE_MAX);
+        NotificationChannel channel4 = new NotificationChannel("id4", "name3",
+                NotificationManager.IMPORTANCE_MAX);
+        channel1.setBypassDnd(false);
+        channel2.setBypassDnd(true);
+        channel3.setBypassDnd(true);
+        channel4.setBypassDnd(false);
+        // has DND access, so can set bypassDnd attribute
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true,
+                /*has DND access*/ true, UID_N_MR1, false);
+        mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, true,
+                UID_O, false);
+        mHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true,
+                UID_P, false);
+        mHelper.createNotificationChannel(PKG_P, UID_P, channel4, true, true,
+                UID_P, false);
+
+        assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_O)))
+                .containsExactlyElementsIn(expected);
+    }
+
+    @Test
     public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() {
         int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
         when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 4b94e10..bf61d06 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -49,6 +49,8 @@
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
 import static android.app.NotificationManager.Policy.STATE_PRIORITY_CHANNELS_BLOCKED;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
+import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.SYSTEM_UID;
 import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
@@ -70,6 +72,7 @@
 import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_ACTIVATE;
 import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_DEACTIVATE;
 import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_NONE;
+import static android.service.notification.ZenModeConfig.implicitRuleId;
 import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
 import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE;
 import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
@@ -84,8 +87,6 @@
 import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG;
 import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW;
 import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES;
 import static com.android.server.notification.ZenModeEventLogger.ACTIVE_RULE_TYPE_MANUAL;
 import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
 
@@ -102,6 +103,7 @@
 
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -5348,6 +5350,22 @@
         mTestableLooper.processAllMessages();
 
         verify(mDeviceEffectsApplier).apply(eq(effects), eq(ORIGIN_APP));
+        assertTrue(mZenModeHelper.hasDeviceEffectsApplier());
+    }
+
+    @Test
+    public void testHasDeviceEffectsApplier_returnsFalseIfNotSet() {
+        assertFalse(mZenModeHelper.hasDeviceEffectsApplier());
+    }
+
+    @Test
+    @EnableFlags(FLAG_MODES_API)
+    public void testSettingDeviceEffects_throwsExceptionIfAlreadySet() {
+        mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier);
+
+        assertThrows(
+                IllegalStateException.class,
+                () -> mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier));
     }
 
     @Test
@@ -7050,6 +7068,50 @@
         assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
     }
 
+    @Test
+    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+    public void setAutomaticZenRuleState_implicitRuleManualActivation_doesNotUseOverride() {
+        mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
+                PERMISSION_GRANTED); // So that canManageAZR succeeds.
+        mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+                CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+                CUSTOM_PKG_UID, ZEN_MODE_OFF);
+        ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+        assertThat(implicitRule.isActive()).isFalse();
+
+        mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id,
+                new Condition(implicitRule.conditionId, "on!", STATE_TRUE, SOURCE_USER_ACTION),
+                ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+
+        implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+        assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id))
+                .isEqualTo(STATE_TRUE);
+        assertThat(implicitRule.isActive()).isTrue();
+        assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
+    }
+
+    @Test
+    @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+    public void setAutomaticZenRuleState_implicitRuleManualDeactivation_doesNotUseOverride() {
+        mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
+                PERMISSION_GRANTED); // So that canManageAZR succeeds.
+        mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME,
+                CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+        assertThat(implicitRule.isActive()).isTrue();
+
+        mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id,
+                new Condition(implicitRule.conditionId, "off!", STATE_FALSE, SOURCE_USER_ACTION),
+                ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+
+        implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME));
+        assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id))
+                .isEqualTo(STATE_FALSE);
+        assertThat(implicitRule.isActive()).isFalse();
+        assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
+    }
+
     private ZenRule getZenRule(String ruleId) {
         return checkNotNull(mZenModeHelper.mConfig.automaticRules.get(ruleId),
                 "Didn't find rule with id %s", ruleId);
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
index 88ed615..81026fd 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/DeviceAdapterTest.java
@@ -16,6 +16,16 @@
 
 package com.android.server.vibrator;
 
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_QUICK_FALL;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_QUICK_RISE;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_SLOW_RISE;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_SPIN;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_THUD;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -38,7 +48,7 @@
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibrationEffectSegment;
 import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.SparseArray;
 
@@ -60,6 +70,7 @@
     private static final int PWLE_VIBRATOR_ID = 2;
     private static final int PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID = 3;
     private static final int PWLE_V2_VIBRATOR_ID = 4;
+    private static final int BASIC_VIBRATOR_ID = 5;
     private static final float TEST_MIN_FREQUENCY = 50;
     private static final float TEST_RESONANT_FREQUENCY = 150;
     private static final float TEST_FREQUENCY_RESOLUTION = 25;
@@ -73,6 +84,7 @@
     private static final float PWLE_V2_MIN_FREQUENCY = TEST_FREQUENCIES_HZ[0];
     private static final float PWLE_V2_MAX_FREQUENCY =
             TEST_FREQUENCIES_HZ[TEST_FREQUENCIES_HZ.length - 1];
+    private static final int TEST_PRIMITIVE_DURATION = 20;
 
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
@@ -104,6 +116,7 @@
         vibrators.put(PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID,
                 createPwleWithoutFrequenciesVibratorController(
                         PWLE_WITHOUT_FREQUENCIES_VIBRATOR_ID));
+        vibrators.put(BASIC_VIBRATOR_ID, createBasicVibratorController(BASIC_VIBRATOR_ID));
         mAdapter = new DeviceAdapter(mVibrationSettings, vibrators);
     }
 
@@ -118,12 +131,12 @@
                 new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100)),
                 /* repeatIndex= */ -1);
 
-        assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isEqualTo(effect);
+        assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isEqualTo(effect);
         assertThat(mAdapter.adaptToVibrator(PWLE_VIBRATOR_ID, effect)).isEqualTo(effect);
     }
 
     @Test
-    @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
     public void testVendorEffect_returnsOriginalSegment() {
         PersistableBundle vendorData = new PersistableBundle();
         vendorData.putInt("key", 1);
@@ -236,10 +249,10 @@
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
                 new PrebakedSegment(
                         VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_LIGHT),
-                new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_TICK, 1, 10),
+                new StepSegment(1, 0, 10),
                 new PrebakedSegment(
                         VibrationEffect.EFFECT_THUD, true, VibrationEffect.EFFECT_STRENGTH_STRONG),
-                new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100)),
+                new StepSegment(1, 0, 10)),
                 /* repeatIndex= */ -1);
 
         CombinedVibration expected = CombinedVibration.createParallel(effect);
@@ -262,6 +275,11 @@
                         new StepSegment(1, 175, 10),
                         new StepSegment(1, 0, 50)),
                         /* repeatIndex= */ 1))
+                .addVibrator(BASIC_VIBRATOR_ID, new VibrationEffect.Composed(Arrays.asList(
+                        // Step(amplitude, frequencyHz, duration)
+                        new StepSegment(1, 175, 10),
+                        new StepSegment(1, 0, 50)),
+                        /* repeatIndex= */ 1))
                 .addVibrator(PWLE_VIBRATOR_ID, new VibrationEffect.Composed(Arrays.asList(
                 // Ramp(startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration)
                         new RampSegment(0.72f, 0.72f, 175, 175, 10),
@@ -308,7 +326,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testPwleSegment_withoutPwleV2Capability_returnsNull() {
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
                 new PrimitiveSegment(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.5f, 100),
@@ -318,12 +336,12 @@
                 /* repeatIndex= */ 1);
 
         VibrationEffect.Composed adaptedEffect =
-                (VibrationEffect.Composed) mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect);
+                (VibrationEffect.Composed) mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect);
         assertThat(adaptedEffect).isNull();
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testPwleSegment_withPwleV2Capability_returnsAdaptedSegments() {
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
                 new PwleSegment(1, 0.2f, 30, 60, 20),
@@ -345,7 +363,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testPwleSegment_withFrequenciesBelowSupportedRange_returnsNull() {
         float frequencyBelowSupportedRange = PWLE_V2_MIN_FREQUENCY - 1f;
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
@@ -362,7 +380,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
+    @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
     public void testPwleSegment_withFrequenciesAboveSupportedRange_returnsNull() {
         float frequencyAboveSupportedRange = PWLE_V2_MAX_FREQUENCY + 1f;
         VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
@@ -378,22 +396,79 @@
         assertThat(adapter.adaptToVibrator(PWLE_V2_VIBRATOR_ID, effect)).isNull();
     }
 
+    @Test
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelay_withoutFlag_returnsNull() {
+        VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1, 100, DELAY_TYPE_RELATIVE_START_OFFSET)),
+                /* repeatIndex= */ -1);
+
+        assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+        assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isNull();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testUnsupportedPrimitives_withFlag_returnsNull() {
+        VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_TICK, 1, 10),
+                new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1, 100)),
+                /* repeatIndex= */ -1);
+
+        assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelay_returnsPrimitiveWithPauseDelays() {
+        int expectedPause = 50;
+        int relativeDelay = 50 + TEST_PRIMITIVE_DURATION - 1;
+        VibrationEffect.Composed effect = new VibrationEffect.Composed(Arrays.asList(
+                // Originally requested (overlapping):
+                // tick @ 10ms / tick @ 11ms / click @ 69ms + 20ms pause + click
+                // Actually played:
+                // 10ms pause + tick + 50ms pause + click + 20ms pause + click
+                new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 1, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1, relativeDelay,
+                        DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.5f, 20, DELAY_TYPE_PAUSE)),
+                /* repeatIndex= */ -1);
+
+        // Delay based on primitive duration
+        VibrationEffect.Composed expected = new VibrationEffect.Composed(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_TICK, 1, 10, DELAY_TYPE_PAUSE),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1, expectedPause, DELAY_TYPE_PAUSE),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.5f, 20, DELAY_TYPE_PAUSE)),
+                /* repeatIndex= */ -1);
+
+        assertThat(mAdapter.adaptToVibrator(EMPTY_VIBRATOR_ID, effect)).isNull();
+        assertThat(mAdapter.adaptToVibrator(BASIC_VIBRATOR_ID, effect)).isEqualTo(expected);
+    }
+
     private VibratorController createEmptyVibratorController(int vibratorId) {
         return new FakeVibratorControllerProvider(mTestLooper.getLooper())
                 .newVibratorController(vibratorId, (id, vibrationId)  -> {});
     }
 
+    private VibratorController createBasicVibratorController(int vibratorId) {
+        FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+                IVibrator.CAP_COMPOSE_EFFECTS);
+        return provider.newVibratorController(vibratorId, (id, vibrationId)  -> {});
+    }
+
     private VibratorController createPwleWithoutFrequenciesVibratorController(int vibratorId) {
-        FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
-                mTestLooper.getLooper());
-        provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+        FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+                IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
         return provider.newVibratorController(vibratorId, (id, vibrationId)  -> {});
     }
 
     private VibratorController createPwleVibratorController(int vibratorId) {
-        FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
-                mTestLooper.getLooper());
-        provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+        FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+                IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
         provider.setResonantFrequency(TEST_RESONANT_FREQUENCY);
         provider.setMinFrequency(TEST_MIN_FREQUENCY);
         provider.setFrequencyResolution(TEST_FREQUENCY_RESOLUTION);
@@ -402,9 +477,8 @@
     }
 
     private VibratorController createPwleV2VibratorController(int vibratorId) {
-        FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
-                mTestLooper.getLooper());
-        provider.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
+        FakeVibratorControllerProvider provider = createVibratorProviderWithEffects(
+                IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
         provider.setResonantFrequency(TEST_RESONANT_FREQUENCY);
         provider.setFrequenciesHz(TEST_FREQUENCIES_HZ);
         provider.setOutputAccelerationsGs(TEST_OUTPUT_ACCELERATIONS_GS);
@@ -414,4 +488,15 @@
 
         return provider.newVibratorController(vibratorId, (id, vibrationId)  -> {});
     }
+
+    private FakeVibratorControllerProvider createVibratorProviderWithEffects(int... capabilities) {
+        FakeVibratorControllerProvider provider = new FakeVibratorControllerProvider(
+                mTestLooper.getLooper());
+        provider.setCapabilities(capabilities);
+        provider.setSupportedPrimitives(PRIMITIVE_CLICK, PRIMITIVE_TICK, PRIMITIVE_THUD,
+                PRIMITIVE_SPIN, PRIMITIVE_QUICK_RISE, PRIMITIVE_QUICK_FALL, PRIMITIVE_SLOW_RISE);
+        provider.setSupportedEffects(VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK);
+        provider.setPrimitiveDuration(TEST_PRIMITIVE_DURATION);
+        return provider;
+    }
 }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java
new file mode 100644
index 0000000..f4a6f82
--- /dev/null
+++ b/services/tests/vibrator/src/com/android/server/vibrator/PrimitiveDelayAdapterTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.server.vibrator;
+
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_PAUSE;
+import static android.os.VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
+import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationEffect;
+import android.os.VibratorInfo;
+import android.os.vibrator.Flags;
+import android.os.vibrator.PrebakedSegment;
+import android.os.vibrator.PrimitiveSegment;
+import android.os.vibrator.RampSegment;
+import android.os.vibrator.StepSegment;
+import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PrimitiveDelayAdapterTest {
+    private static final VibratorInfo EMPTY_VIBRATOR_INFO = new VibratorInfo.Builder(0).build();
+    private static final VibratorInfo BASIC_VIBRATOR_INFO = createVibratorInfoWithPrimitives(
+            new int[] { PRIMITIVE_CLICK, PRIMITIVE_TICK },
+            new int[] { 20, 10 });
+
+    private PrimitiveDelayAdapter mAdapter;
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Before
+    public void setUp() throws Exception {
+        mAdapter = new PrimitiveDelayAdapter();
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveSegments_flagDisabled_keepsListUnchanged() {
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_PAUSE)));
+        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+        assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+        assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+        assertEquals(originalSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testNonPrimitiveSegments_keepsListUnchanged() {
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+                new RampSegment(/* startAmplitude= */ 0.8f, /* endAmplitude= */ 0.2f,
+                        /* startFrequencyHz= */ 100, /* endFrequencyHz= */ 1, /* duration= */ 20),
+                new PrebakedSegment(VibrationEffect.EFFECT_CLICK, false,
+                        VibrationEffect.EFFECT_STRENGTH_LIGHT)));
+        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+        assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+        assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+        assertEquals(originalSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithPause_keepsListUnchanged() {
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 100, DELAY_TYPE_PAUSE),
+                new PrimitiveSegment(PRIMITIVE_TICK, 0.5f, 10, DELAY_TYPE_PAUSE)));
+        List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments);
+
+        assertEquals(-1, mAdapter.adaptToVibrator(EMPTY_VIBRATOR_INFO, segments, -1));
+        assertEquals(1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, 1));
+
+        assertEquals(originalSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelay_afterPrimitive_usesPrimitiveStartTimeForDelay() {
+        VibratorInfo info = createVibratorInfoWithPrimitives(
+                new int[] { PRIMITIVE_CLICK }, new int[] { 20 });
+
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.2f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 0, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+        List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_PAUSE),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 0, DELAY_TYPE_PAUSE)));
+
+        // Repeat index is fixed after removals
+        assertEquals(-1, mAdapter.adaptToVibrator(info, segments, -1));
+
+        assertEquals(expectedSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelay_afterRepeatIndex_usesPauseAsFirstDelay() {
+        VibratorInfo info = createVibratorInfoWithPrimitives(
+                new int[] { PRIMITIVE_CLICK }, new int[] { 20 });
+
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.2f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 10, DELAY_TYPE_RELATIVE_START_OFFSET),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.4f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+        List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.1f, 100, DELAY_TYPE_PAUSE),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 0.3f, 10, DELAY_TYPE_PAUSE)));
+
+        // Relative offset reset after repeat index.
+        assertEquals(1, mAdapter.adaptToVibrator(info, segments, 2));
+
+        assertEquals(expectedSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelayAfter_afterStep_usesSegmentStartTimeForDelay() {
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+        List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+                new StepSegment(/* amplitude= */ 0, /* frequencyHz= */ 1, /* duration= */ 10),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 0, DELAY_TYPE_PAUSE)));
+
+        assertEquals(-1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, -1));
+        assertEquals(expectedSegments, segments);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void testPrimitiveWithRelativeDelayAfter_afterUnknownDuration_usesZeroAsDuration() {
+        List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+                new PrebakedSegment(VibrationEffect.EFFECT_POP, false,
+                        VibrationEffect.EFFECT_STRENGTH_STRONG),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_RELATIVE_START_OFFSET)));
+
+        assertEquals(-1, mAdapter.adaptToVibrator(BASIC_VIBRATOR_INFO, segments, -1));
+
+        List<VibrationEffectSegment> expectedSegments = new ArrayList<>(Arrays.asList(
+                new PrebakedSegment(VibrationEffect.EFFECT_POP, false,
+                        VibrationEffect.EFFECT_STRENGTH_STRONG),
+                new PrimitiveSegment(PRIMITIVE_CLICK, 1f, 10, DELAY_TYPE_PAUSE)));
+
+        assertEquals(expectedSegments, segments);
+    }
+
+    private static VibratorInfo createVibratorInfoWithPrimitives(int[] ids, int[] durations) {
+        VibratorInfo.Builder builder = new VibratorInfo.Builder(0)
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+
+        for (int i = 0; i < ids.length; i++) {
+            builder.setSupportedPrimitive(ids[i], durations[i]);
+        }
+
+        return builder.build();
+    }
+}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 0933590..eb44daa 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -747,7 +747,8 @@
     }
 
     @Test
-    public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void vibrate_singleVibratorComposedAndNoCapability_triggersHalAndReturnsUnsupported() {
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
                 .compose();
@@ -762,6 +763,22 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+                .compose();
+        HalVibration vibration = startThreadAndDispatcher(effect);
+        waitForCompletion();
+
+        verify(mManagerHooks, never()).noteVibratorOn(eq(UID), anyLong());
+        verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
+        verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibration.id));
+        verifyCallbacksTriggered(vibration, Status.IGNORED_UNSUPPORTED);
+        assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibration.id).isEmpty());
+    }
+
+    @Test
     public void vibrate_singleVibratorLargeComposition_splitsVibratorComposeCalls() {
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
         fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -887,7 +904,7 @@
         fakeVibrator.setMaxEnvelopeEffectSize(10);
         fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
 
-        VibrationEffect effect = VibrationEffect.startWaveformEnvelope()
+        VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
                 .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
@@ -922,12 +939,14 @@
         fakeVibrator.setMaxEnvelopeEffectSize(10);
         fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20);
 
-        VibrationEffect effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30)
+        VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder()
+                .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30)
                 .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30)
                 .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20)
                 .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30)
                 .build();
+
         HalVibration vibration = startThreadAndDispatcher(effect);
         waitForCompletion();
 
@@ -1913,6 +1932,55 @@
                 fakeVibrator.getEffectSegments(vibration5.id));
     }
 
+    @Test
+    public void vibrate_multipleVibratorsSequentialInSession_runsInOrderWithoutDelaysAndNoOffs() {
+        mockVibrators(1, 2, 3);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
+        mVibratorProviders.get(3).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+
+        CombinedVibration effect = CombinedVibration.startSequential()
+                .addNext(3,
+                        VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+                        /* delay= */ TEST_TIMEOUT_MILLIS)
+                .addNext(1,
+                        VibrationEffect.createWaveform(
+                                new long[] {TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS},
+                                /* repeat= */ -1),
+                        /* delay= */ TEST_TIMEOUT_MILLIS)
+                .addNext(2,
+                        VibrationEffect.startComposition()
+                                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1,
+                                        /* delay= */ TEST_TIMEOUT_MILLIS)
+                                .compose(),
+                        /* delay= */ TEST_TIMEOUT_MILLIS)
+                .combine();
+        HalVibration vibration = startThreadAndDispatcher(effect, /* isInSession= */ true);
+
+        // Should not timeout as delays will not affect in session playback time.
+        waitForCompletion();
+
+        // Vibrating state remains ON until session resets it.
+        verifyCallbacksTriggered(vibration, Status.FINISHED);
+        assertTrue(mControllers.get(1).isVibrating());
+        assertTrue(mControllers.get(2).isVibrating());
+        assertTrue(mControllers.get(3).isVibrating());
+
+        assertEquals(0, mVibratorProviders.get(1).getOffCount());
+        assertEquals(0, mVibratorProviders.get(2).getOffCount());
+        assertEquals(0, mVibratorProviders.get(3).getOffCount());
+        assertEquals(Arrays.asList(expectedOneShot(TEST_TIMEOUT_MILLIS)),
+                mVibratorProviders.get(1).getEffectSegments(vibration.id));
+        assertEquals(expectedAmplitudes(255), mVibratorProviders.get(1).getAmplitudes());
+        assertEquals(Arrays.asList(expectedPrimitive(
+                VibrationEffect.Composition.PRIMITIVE_CLICK, 1, TEST_TIMEOUT_MILLIS)),
+                mVibratorProviders.get(2).getEffectSegments(vibration.id));
+        assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
+                mVibratorProviders.get(3).getEffectSegments(vibration.id));
+    }
+
     private void mockVibrators(int... vibratorIds) {
         for (int vibratorId : vibratorIds) {
             mVibratorProviders.put(vibratorId,
@@ -1935,8 +2003,14 @@
         return startThreadAndDispatcher(createVibration(effect));
     }
 
+    private HalVibration startThreadAndDispatcher(CombinedVibration effect, boolean isInSession) {
+        return startThreadAndDispatcher(createVibration(effect), isInSession,
+                /* requestVibrationParamsFuture= */ null);
+    }
+
     private HalVibration startThreadAndDispatcher(HalVibration vib) {
-        return startThreadAndDispatcher(vib, /* requestVibrationParamsFuture= */ null);
+        return startThreadAndDispatcher(vib, /* isInSession= */ false,
+                /* requestVibrationParamsFuture= */ null);
     }
 
     private HalVibration startThreadAndDispatcher(VibrationEffect effect,
@@ -1947,15 +2021,17 @@
         HalVibration vib = new HalVibration(
                 new CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"),
                 CombinedVibration.createParallel(effect));
-        return startThreadAndDispatcher(vib, requestVibrationParamsFuture);
+        return startThreadAndDispatcher(vib, /* isInSession= */ false,
+                requestVibrationParamsFuture);
     }
 
-    private HalVibration startThreadAndDispatcher(HalVibration vib,
+    private HalVibration startThreadAndDispatcher(HalVibration vib, boolean isInSession,
             CompletableFuture<Void> requestVibrationParamsFuture) {
         mControllers = createVibratorControllers();
         DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, mControllers);
-        mVibrationConductor = new VibrationStepConductor(vib, mVibrationSettings, deviceAdapter,
-                mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture, mManagerHooks);
+        mVibrationConductor = new VibrationStepConductor(vib, isInSession, mVibrationSettings,
+                deviceAdapter, mVibrationScaler, mStatsLoggerMock, requestVibrationParamsFuture,
+                mManagerHooks);
         assertTrue(mThread.runVibrationOnVibrationThread(mVibrationConductor));
         return mVibrationConductor.getVibration();
     }
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 88ba9e3..ec83e99 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1531,6 +1531,8 @@
         FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
         fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        mVibratorProviders.get(2).setSupportedPrimitives(
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
         CombinedVibration effect = CombinedVibration.startParallel()
@@ -2115,7 +2117,8 @@
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(1).setSupportedPrimitives(
-                VibrationEffect.Composition.PRIMITIVE_CLICK);
+                VibrationEffect.Composition.PRIMITIVE_CLICK,
+                VibrationEffect.Composition.PRIMITIVE_TICK);
 
         VibratorManagerService service = createSystemReadyService();
         vibrateAndWaitUntilFinished(service,
@@ -2132,9 +2135,10 @@
         assertTrue(segments.size() > 2);
         // 0: Supported effect played
         assertTrue(segments.get(0) instanceof PrebakedSegment);
-        // 1: No segment for unsupported primitive
+        // 1: Supported primitive played
+        assertTrue(segments.get(1) instanceof PrimitiveSegment);
         // 2: One or more intermediate step segments as fallback for unsupported effect
-        for (int i = 1; i < segments.size() - 1; i++) {
+        for (int i = 2; i < segments.size() - 1; i++) {
             assertTrue(segments.get(i) instanceof StepSegment);
         }
         // 3: Supported primitive played
@@ -2861,7 +2865,7 @@
         mTestLooper.dispatchAll();
 
         assertThat(session.getStatus()).isEqualTo(Status.IGNORED_UNSUPPORTED);
-        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 3}));
+        verify(mNativeWrapperMock, never()).startSession(anyLong(), any(int[].class));
         verify(callback, never()).onStarted(any(IVibrationSession.class));
         verify(callback, never()).onFinishing();
         verify(callback)
@@ -2885,6 +2889,7 @@
         verify(callback).onStarted(captor.capture());
 
         captor.getValue().finishSession();
+        mTestLooper.dispatchAll();
 
         // Session not ended until HAL callback.
         assertThat(session.getStatus()).isEqualTo(Status.RUNNING);
@@ -3135,6 +3140,224 @@
     }
 
     @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    public void vibrateInSession_afterCancel_vibrationIgnored() throws Exception {
+        mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+        mockVibrators(1, 2);
+        FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+        fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+        int sessionFinishDelayMs = 200;
+        IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+        VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+        mTestLooper.dispatchAll();
+
+        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+        ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+        verify(callback).onStarted(captor.capture());
+
+        IVibrationSession startedSession = captor.getValue();
+        startedSession.cancelSession();
+        startedSession.vibrate(
+                CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+                "reason");
+
+        // VibrationThread will never start this vibration.
+        assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+                TEST_TIMEOUT_MILLIS));
+
+        // Dispatch HAL callbacks.
+        mTestLooper.moveTimeForward(sessionFinishDelayMs);
+        mTestLooper.dispatchAll();
+
+        assertThat(session.getStatus()).isEqualTo(Status.CANCELLED_BY_USER);
+        verify(callback).onFinishing();
+        verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_CANCELED));
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    public void vibrateInSession_afterFinish_vibrationIgnored() throws Exception {
+        mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+        mockVibrators(1, 2);
+        FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+        fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+        int sessionFinishDelayMs = 200;
+        IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+        VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+        mTestLooper.dispatchAll();
+
+        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+        ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+        verify(callback).onStarted(captor.capture());
+
+        IVibrationSession startedSession = captor.getValue();
+        startedSession.finishSession();
+        mTestLooper.dispatchAll();
+
+        startedSession.vibrate(
+                CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+                "reason");
+
+        // Session not ended until HAL callback.
+        assertThat(session.getStatus()).isEqualTo(Status.RUNNING);
+
+        // VibrationThread will never start this vibration.
+        assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+                TEST_TIMEOUT_MILLIS));
+
+        // Dispatch HAL callbacks.
+        mTestLooper.moveTimeForward(sessionFinishDelayMs);
+        mTestLooper.dispatchAll();
+
+        assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+        verify(callback).onFinishing();
+        verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    public void vibrateInSession_repeatingVibration_vibrationIgnored() throws Exception {
+        mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+        mockVibrators(1, 2);
+        FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+        fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+        int sessionFinishDelayMs = 200;
+        IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+        VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+        mTestLooper.dispatchAll();
+
+        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+        ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+        verify(callback).onStarted(captor.capture());
+
+        IVibrationSession startedSession = captor.getValue();
+        startedSession.vibrate(
+                CombinedVibration.createParallel(
+                        VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, 0)),
+                "reason");
+
+        // VibrationThread will never start this vibration.
+        assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service,
+                TEST_TIMEOUT_MILLIS));
+
+        startedSession.finishSession();
+        mTestLooper.dispatchAll();
+
+        // Dispatch HAL callbacks.
+        mTestLooper.moveTimeForward(sessionFinishDelayMs);
+        mTestLooper.dispatchAll();
+
+        assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+        assertThat(service.isVibrating(1)).isFalse();
+        assertThat(service.isVibrating(2)).isFalse();
+        verify(callback).onFinishing();
+        verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    public void vibrateInSession_singleVibration_playsAllVibrateCommands() throws Exception {
+        mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+        mockVibrators(1, 2);
+        FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+        fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator2 = mVibratorProviders.get(1);
+        fakeVibrator2.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+        int sessionFinishDelayMs = 200;
+        IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+        VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+        mTestLooper.dispatchAll();
+
+        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+        ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+        verify(callback).onStarted(captor.capture());
+
+        IVibrationSession startedSession = captor.getValue();
+        startedSession.vibrate(
+                CombinedVibration.createParallel(
+                        VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, -1)),
+                "reason");
+
+        // VibrationThread will start this vibration async, so wait until vibration is triggered.
+        // Vibrators will receive 2 requests for the waveform playback
+        assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
+        assertTrue(waitUntil(s -> fakeVibrator2.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
+
+        startedSession.finishSession();
+        mTestLooper.dispatchAll();
+
+        // Dispatch HAL callbacks.
+        mTestLooper.moveTimeForward(sessionFinishDelayMs);
+        mTestLooper.dispatchAll();
+
+        assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+        assertThat(service.isVibrating(1)).isFalse();
+        assertThat(service.isVibrating(2)).isFalse();
+        verify(callback).onFinishing();
+        verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+    }
+
+    @Test
+    @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS)
+    public void vibrateInSession_multipleVibrations_playsAllVibrations() throws Exception {
+        mockCapabilities(IVibratorManager.CAP_START_SESSIONS);
+        mockVibrators(1, 2);
+        FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
+        fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        VibratorManagerService service = createSystemReadyService();
+        int sessionFinishDelayMs = 200;
+        IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs);
+
+        VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2);
+        mTestLooper.dispatchAll();
+
+        verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2}));
+        ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class);
+        verify(callback).onStarted(captor.capture());
+
+        IVibrationSession startedSession = captor.getValue();
+        startedSession.vibrate(
+                CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)),
+                "reason");
+
+        // VibrationThread will start this vibration async, so wait until vibration is completed.
+        assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 1, service,
+                TEST_TIMEOUT_MILLIS));
+        assertTrue(waitUntil(s -> !session.getVibrations().isEmpty(), service,
+                TEST_TIMEOUT_MILLIS));
+
+        startedSession.vibrate(
+                CombinedVibration.createParallel(VibrationEffect.createOneShot(20, 255)),
+                "reason");
+
+        assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
+
+        startedSession.finishSession();
+        mTestLooper.dispatchAll();
+
+        // Dispatch HAL callbacks.
+        mTestLooper.moveTimeForward(sessionFinishDelayMs);
+        mTestLooper.dispatchAll();
+
+        assertThat(session.getStatus()).isEqualTo(Status.FINISHED);
+        assertThat(service.isVibrating(1)).isFalse();
+        assertThat(service.isVibrating(2)).isFalse();
+        verify(callback).onFinishing();
+        verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS));
+    }
+
+    @Test
     public void frameworkStats_externalVibration_reportsAllMetrics() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
@@ -3277,7 +3500,8 @@
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(1).setSupportedPrimitives(
-                VibrationEffect.Composition.PRIMITIVE_TICK);
+                VibrationEffect.Composition.PRIMITIVE_TICK,
+                VibrationEffect.Composition.PRIMITIVE_CLICK);
 
         VibratorManagerService service = createSystemReadyService();
         vibrateAndWaitUntilFinished(service,
@@ -3320,10 +3544,12 @@
         assertEquals(3, metrics.halPerformCount); // CLICK, TICK, then CLICK
         assertEquals(4, metrics.halCompositionSize); // 2*TICK + 2*CLICK
         // No repetitions in reported effect/primitive IDs.
-        assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_TICK},
+        assertArrayEquals(
+                new int[] {
+                        VibrationEffect.Composition.PRIMITIVE_CLICK,
+                        VibrationEffect.Composition.PRIMITIVE_TICK,
+                },
                 metrics.halSupportedCompositionPrimitivesUsed);
-        assertArrayEquals(new int[] {VibrationEffect.Composition.PRIMITIVE_CLICK},
-                metrics.halUnsupportedCompositionPrimitivesUsed);
         assertArrayEquals(new int[] {VibrationEffect.EFFECT_CLICK},
                 metrics.halSupportedEffectsUsed);
         assertArrayEquals(new int[] {VibrationEffect.EFFECT_TICK},
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 4dc59c2..3f34767 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -236,7 +236,7 @@
             infoBuilder.setSupportedEffects(mSupportedEffects);
             if (mSupportedPrimitives != null) {
                 for (int primitive : mSupportedPrimitives) {
-                    infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION);
+                    infoBuilder.setSupportedPrimitive(primitive, (int) mPrimitiveDuration);
                 }
             }
             infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml
index 197b366..787f4e8 100644
--- a/services/tests/wmtests/res/xml/bookmarks.xml
+++ b/services/tests/wmtests/res/xml/bookmarks.xml
@@ -13,60 +13,70 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <!-- the key combinations for the following shortcuts must be in sync
          with the key combinations sent by the test in ModifierShortcutTests.java -->
     <bookmark
         role="android.app.role.BROWSER"
-        shortcut="b" />
+        androidprv:keycode="KEYCODE_B"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CONTACTS"
-        shortcut="c" />
+        androidprv:keycode="KEYCODE_C"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_EMAIL"
-        shortcut="e" />
+        androidprv:keycode="KEYCODE_E"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALENDAR"
-        shortcut="k" />
+        androidprv:keycode="KEYCODE_K"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MAPS"
-        shortcut="m" />
+        androidprv:keycode="KEYCODE_M"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MUSIC"
-        shortcut="p" />
+        androidprv:keycode="KEYCODE_P"
+        androidprv:modifierState="META" />
     <bookmark
         role="android.app.role.SMS"
-        shortcut="s" />
+        androidprv:keycode="KEYCODE_S"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALCULATOR"
-        shortcut="u" />
+        androidprv:keycode="KEYCODE_U"
+        androidprv:modifierState="META" />
 
     <bookmark
         role="android.app.role.BROWSER"
-        shortcut="b"
-        shift="true" />
+        androidprv:keycode="KEYCODE_B"
+        androidprv:modifierState="META|SHIFT" />
 
     <bookmark
         category="android.intent.category.APP_CONTACTS"
-        shortcut="c"
-        shift="true" />
+        androidprv:keycode="KEYCODE_C"
+        androidprv:modifierState="META|SHIFT" />
 
     <bookmark
         package="com.test"
         class="com.test.BookmarkTest"
-        shortcut="j"
-        shift="true" />
+        androidprv:keycode="KEYCODE_J"
+        androidprv:modifierState="META|SHIFT" />
 
     <!-- The following shortcuts will not be invoked by tests but are here to
          provide test coverage of parsing the different types of shortcut. -->
     <bookmark
         package="com.test"
         class="com.test.BookmarkTest"
-        shortcut="j" />
+        androidprv:keycode="KEYCODE_J"
+        androidprv:modifierState="META" />
     <bookmark
         package="com.test2"
         class="com.test.BookmarkTest"
-        shortcut="d" />
+        androidprv:keycode="KEYCODE_D"
+        androidprv:modifierState="META" />
 
 
     <!-- It's intended that this package/class will NOT resolve so we test the resolution
@@ -74,6 +84,7 @@
     <bookmark
         package="com.test3"
         class="com.test.BookmarkTest"
-        shortcut="f" />
+        androidprv:keycode="KEYCODE_F"
+        androidprv:modifierState="META" />
 
 </bookmarks>
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
index 0575d98..82a5add 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -116,6 +116,7 @@
 
         mModifierShortcutManager = new ModifierShortcutManager(
                 mContext, mHandler, UserHandle.SYSTEM);
+        mModifierShortcutManager.onSystemReady();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index a51ce995..bc03c23 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -88,6 +88,7 @@
 import android.telecom.TelecomManager;
 import android.view.Display;
 import android.view.InputEvent;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.autofill.AutofillManagerInternal;
@@ -270,11 +271,15 @@
         // Return mocked services: LocalServices.getService
         mMockitoSession = mockitoSession()
                 .mockStatic(LocalServices.class, spyStubOnly)
+                .mockStatic(KeyCharacterMap.class)
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
         mPhoneWindowManager = spy(new PhoneWindowManager());
 
+        KeyCharacterMap virtualKcm = mContext.getSystemService(InputManager.class)
+                .getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD).getKeyCharacterMap();
+        doReturn(virtualKcm).when(() -> KeyCharacterMap.load(anyInt()));
         doReturn(mWindowManagerInternal).when(
                 () -> LocalServices.getService(eq(WindowManagerInternal.class)));
         doReturn(mActivityManagerInternal).when(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 42e31de..817c368 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -82,6 +82,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
@@ -122,6 +123,8 @@
  * Build/Install/Run:
  *  atest WmTests:WindowOrganizerTests
  */
+
+// TODO revert parts of this set to set the flag to test the behavior
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
@@ -1299,6 +1302,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
     public void testEnterPipParams() {
         final StubOrganizer o = new StubOrganizer();
         mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o);
@@ -1314,6 +1318,7 @@
     }
 
     @Test
+    @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
     public void testChangePipParams() {
         class ChangeSavingOrganizer extends StubOrganizer {
             RunningTaskInfo mChangedInfo;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 1750a14..50e0e18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -71,6 +71,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -84,12 +85,14 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.when;
 
+import android.content.ContentResolver;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.InputConfig;
 import android.os.RemoteException;
@@ -97,6 +100,7 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.MergedConfiguration;
 import android.view.Gravity;
@@ -353,6 +357,29 @@
     }
 
     @Test
+    public void testDestroySurface() {
+        final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+        win.mHasSurface = win.mAnimatingExit = true;
+        win.mWinAnimator.mSurfaceControl = mock(SurfaceControl.class);
+        win.onExitAnimationDone();
+
+        assertFalse("Case 1 destroySurface no-op",
+                win.destroySurface(false /* cleanupOnResume */, false /* appStopped */));
+        assertTrue(win.mHasSurface);
+        assertTrue(win.mDestroying);
+
+        assertFalse("Case 2 destroySurface no-op",
+                win.destroySurface(true /* cleanupOnResume */, false /* appStopped */));
+        assertTrue(win.mHasSurface);
+        assertTrue(win.mDestroying);
+
+        assertTrue("Case 3 destroySurface destroys surface",
+                win.destroySurface(false /* cleanupOnResume */, true /* appStopped */));
+        assertFalse(win.mDestroying);
+        assertFalse(win.mHasSurface);
+    }
+
+    @Test
     public void testPrepareWindowToDisplayDuringRelayout() {
         // Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON before
         // calling setCurrentLaunchCanTurnScreenOn for windows with flag in the same activity.
@@ -1534,6 +1561,57 @@
     }
 
     @Test
+    public void testIsSecureLocked_flagSecureSet() {
+        WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+                1 /* ownerId */);
+        window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+
+        assertTrue(window.isSecureLocked());
+    }
+
+    @Test
+    public void testIsSecureLocked_flagSecureNotSet() {
+        WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+                1 /* ownerId */);
+
+        assertFalse(window.isSecureLocked());
+    }
+
+    @Test
+    public void testIsSecureLocked_disableSecureWindows() {
+        assumeTrue(Build.IS_DEBUGGABLE);
+
+        WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window",
+                1 /* ownerId */);
+        window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+        ContentResolver cr = useFakeSettingsProvider();
+
+        // isSecureLocked should return false when DISABLE_SECURE_WINDOWS is set to 1
+        Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
+        mWm.mSettingsObserver.onChange(false /* selfChange */,
+                Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+        assertFalse(window.isSecureLocked());
+
+        // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is set to 0.
+        Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "0");
+        mWm.mSettingsObserver.onChange(false /* selfChange */,
+                Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+        assertTrue(window.isSecureLocked());
+
+        // Disable secure windows again.
+        Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1");
+        mWm.mSettingsObserver.onChange(false /* selfChange */,
+                Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+        assertFalse(window.isSecureLocked());
+
+        // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is deleted.
+        Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, null);
+        mWm.mSettingsObserver.onChange(false /* selfChange */,
+                Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS));
+        assertTrue(window.isSecureLocked());
+    }
+
+    @Test
     @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION)
     public void testIsSecureLocked_sensitiveContentProtectionManagerEnabled() {
         String testPackage = "test";
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1294945..15c8b13 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -185,6 +185,7 @@
     private static final int MSG_INCREASE_SENDSTRING_COUNT = 21;
     private static final int MSG_UPDATE_USB_SPEED = 22;
     private static final int MSG_UPDATE_HAL_VERSION = 23;
+    private static final int MSG_USER_UNLOCKED_AFTER_BOOT = 24;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
@@ -414,6 +415,17 @@
             }
         };
 
+        if (Flags.checkUserActionUnlocked()) {
+            BroadcastReceiver userUnlockedAfterBootReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mHandler.sendEmptyMessage(MSG_USER_UNLOCKED_AFTER_BOOT);
+                }
+            };
+            mContext.registerReceiver(userUnlockedAfterBootReceiver,
+                    new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+        }
+
         mContext.registerReceiver(portReceiver,
                 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
         mContext.registerReceiver(chargingReceiver,
@@ -474,6 +486,7 @@
         mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
     }
 
+    // Same as ACTION_LOCKED_BOOT_COMPLETED.
     public void bootCompleted() {
         if (DEBUG) Slog.d(TAG, "boot completed");
         mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
@@ -632,7 +645,7 @@
         protected int mUsbSpeed;
         protected int mCurrentGadgetHalVersion;
         protected boolean mPendingBootAccessoryHandshakeBroadcast;
-
+        protected boolean mUserUnlockedAfterBoot;
         /**
          * The persistent property which stores whether adb is enabled or not.
          * May also contain vendor-specific default functions for testing purposes.
@@ -837,6 +850,12 @@
             return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
         }
 
+        private void attachAccessory() {
+            mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
+            removeMessages(MSG_ACCESSORY_HANDSHAKE_TIMEOUT);
+            broadcastUsbAccessoryHandshake();
+        }
+
         private void updateCurrentAccessory() {
             // We are entering accessory mode if we have received a request from the host
             // and the request has not timed out yet.
@@ -863,10 +882,13 @@
 
                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
                     // defer accessoryAttached if system is not ready
-                    if (mBootCompleted) {
-                        mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
-                        removeMessages(MSG_ACCESSORY_HANDSHAKE_TIMEOUT);
-                        broadcastUsbAccessoryHandshake();
+                    if (!Flags.checkUserActionUnlocked() && mBootCompleted) {
+                        attachAccessory();
+                    }
+                    // Defer accessoryAttached till user unlocks after boot.
+                    // When no pin pattern is set, ACTION_USER_UNLOCKED would fire anyways
+                    if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
+                        attachAccessory();
                     } // else handle in boot completed
                 } else {
                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
@@ -887,7 +909,10 @@
             setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
 
             if (mCurrentAccessory != null) {
-                if (mBootCompleted) {
+                if (!Flags.checkUserActionUnlocked() && mBootCompleted) {
+                    mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
+                }
+                if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
                     mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
                 }
                 mCurrentAccessory = null;
@@ -1377,6 +1402,7 @@
                 case MSG_BOOT_COMPLETED:
                     operationId = sUsbOperationCount.incrementAndGet();
                     mBootCompleted = true;
+                    if (DEBUG) Slog.d(TAG, "MSG_BOOT_COMPLETED");
                     finishBoot(operationId);
                     break;
                 case MSG_USER_SWITCHED: {
@@ -1423,14 +1449,38 @@
                 }
                 case MSG_INCREASE_SENDSTRING_COUNT: {
                     mSendStringCount = mSendStringCount + 1;
+                    break;
+                }
+                case MSG_USER_UNLOCKED_AFTER_BOOT: {
+                    if (DEBUG) Slog.d(TAG, "MSG_USER_UNLOCKED_AFTER_BOOT");
+                    if (mUserUnlockedAfterBoot) {
+                        break;
+                    }
+                    mUserUnlockedAfterBoot = true;
+                    if (mCurrentUsbFunctionsReceived && mUserUnlockedAfterBoot) {
+                        attachAccessoryAfterBoot();
+                    }
+                    break;
                 }
             }
         }
 
+        private void attachAccessoryAfterBoot() {
+            if (mCurrentAccessory != null) {
+                Slog.i(TAG, "AccessoryAttached");
+                mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
+                broadcastUsbAccessoryHandshake();
+            } else if (mPendingBootAccessoryHandshakeBroadcast) {
+                broadcastUsbAccessoryHandshake();
+            }
+            mPendingBootAccessoryHandshakeBroadcast = false;
+        }
+
         public abstract void handlerInitDone(int operationId);
 
         protected void finishBoot(int operationId) {
             if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
+                if (DEBUG) Slog.d(TAG, "finishBoot all flags true");
                 if (mPendingBootBroadcast) {
                     updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                     mPendingBootBroadcast = false;
@@ -1441,14 +1491,12 @@
                 } else {
                     setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                 }
-                if (mCurrentAccessory != null) {
-                    mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
-                    broadcastUsbAccessoryHandshake();
-                } else if (mPendingBootAccessoryHandshakeBroadcast) {
-                    broadcastUsbAccessoryHandshake();
+                if (!Flags.checkUserActionUnlocked()) {
+                    attachAccessoryAfterBoot();
                 }
-
-                mPendingBootAccessoryHandshakeBroadcast = false;
+                if (Flags.checkUserActionUnlocked() && mUserUnlockedAfterBoot) {
+                    attachAccessoryAfterBoot();
+                }
                 updateUsbNotification(false);
                 updateAdbNotification(false);
                 updateUsbFunctions();
diff --git a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
index cd96d76..a2d0efd 100644
--- a/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
+++ b/services/usb/java/com/android/server/usb/flags/usb_flags.aconfig
@@ -14,3 +14,10 @@
     description: "This flag enables binding to MtpService when in mtp/ptp modes"
     bug: "332256525"
 }
+
+flag {
+    name: "check_user_action_unlocked"
+    namespace: "usb"
+    description: "This flag checks if phone is unlocked after boot"
+    bug: "73654179"
+}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index ea61ad9..2c998c4 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.helpers
 
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
 import android.content.Context
 import android.graphics.Insets
 import android.graphics.Rect
@@ -74,13 +75,28 @@
             .waitForAndVerify()
     }
 
+    /** Launch an app and ensure it's moved to Desktop if it has not. */
+    fun enterDesktopMode(
+        wmHelper: WindowManagerStateHelper,
+        device: UiDevice,
+        motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH),
+    ) {
+        innerHelper.launchViaIntent(wmHelper)
+        if (!isInDesktopWindowingMode(wmHelper)) {
+            enterDesktopModeWithDrag(
+                wmHelper = wmHelper,
+                device = device,
+                motionEventHelper = motionEventHelper
+            )
+        }
+    }
+
     /** Move an app to Desktop by dragging the app handle at the top. */
-    fun enterDesktopWithDrag(
+    fun enterDesktopModeWithDrag(
         wmHelper: WindowManagerStateHelper,
         device: UiDevice,
         motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH)
     ) {
-        innerHelper.launchViaIntent(wmHelper)
         dragToDesktop(
             wmHelper = wmHelper,
             device = device,
@@ -150,6 +166,25 @@
             .waitForAndVerify()
     }
 
+    private fun getHeaderEmptyView(caption: UiObject2?): UiObject2 {
+        return caption
+            ?.children
+            ?.find { it.resourceName.endsWith(HEADER_EMPTY_VIEW) }
+            ?: error("Unable to find resource $HEADER_EMPTY_VIEW\n")
+    }
+
+    /** Click on an existing window's header to bring it to the front. */
+    fun bringToFront(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+        val caption = getCaptionForTheApp(wmHelper, device)
+        val openHeaderView = getHeaderEmptyView(caption)
+        openHeaderView.click()
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withTopVisibleApp(innerHelper)
+            .waitForAndVerify()
+    }
+
     /** Open maximize menu and click snap resize button on the app header for the given app. */
     fun snapResizeDesktopApp(
         wmHelper: WindowManagerStateHelper,
@@ -347,6 +382,14 @@
         waitForTransitionToFullscreen(wmHelper)
     }
 
+    /** Maximize an app by dragging the app handle to the top drag zone. */
+    fun maximizeAppWithDragToTopDragZone(
+        wmHelper: WindowManagerStateHelper,
+        device: UiDevice,
+    ) {
+        dragAppWindowToTopDragZone(wmHelper, device)
+    }
+
     private fun dragAppWindowToTopDragZone(wmHelper: WindowManagerStateHelper, device: UiDevice) {
         val windowRect = wmHelper.getWindowRegion(innerHelper).bounds
         val displayRect = getDisplayRect(wmHelper)
@@ -407,6 +450,10 @@
         return metricInsets.getInsetsIgnoringVisibility(typeMask)
     }
 
+    // Requirement of DesktopWindowingMode is having a minimum of 1 app in WINDOWING_MODE_FREEFORM.
+    private fun isInDesktopWindowingMode(wmHelper: WindowManagerStateHelper) =
+        wmHelper.getWindow(innerHelper)?.windowingMode == WINDOWING_MODE_FREEFORM
+
     private companion object {
         val TIMEOUT: Duration = Duration.ofSeconds(3)
         const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge
@@ -419,6 +466,7 @@
         const val SNAP_LEFT_BUTTON: String = "maximize_menu_snap_left_button"
         const val SNAP_RIGHT_BUTTON: String = "maximize_menu_snap_right_button"
         const val MINIMIZE_BUTTON_VIEW: String = "minimize_window"
+        const val HEADER_EMPTY_VIEW: String = "caption_handle"
         val caption: BySelector
             get() = By.res(SYSTEMUI_PACKAGE, CAPTION)
     }
diff --git a/tests/Input/res/xml/bookmarks.xml b/tests/Input/res/xml/bookmarks.xml
index ba3f187..a4c898d 100644
--- a/tests/Input/res/xml/bookmarks.xml
+++ b/tests/Input/res/xml/bookmarks.xml
@@ -14,47 +14,55 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<bookmarks>
+<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <!-- the key combinations for the following shortcuts must be in sync
          with the key combinations sent by the test in KeyGestureControllerTests.java -->
     <bookmark
         role="android.app.role.BROWSER"
-        shortcut="b" />
+        androidprv:keycode="KEYCODE_B"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CONTACTS"
-        shortcut="c" />
+        androidprv:keycode="KEYCODE_C"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_EMAIL"
-        shortcut="e" />
+        androidprv:keycode="KEYCODE_E"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALENDAR"
-        shortcut="k" />
+        androidprv:keycode="KEYCODE_K"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MAPS"
-        shortcut="m" />
+        androidprv:keycode="KEYCODE_M"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_MUSIC"
-        shortcut="p" />
+        androidprv:keycode="KEYCODE_P"
+        androidprv:modifierState="META" />
     <bookmark
         role="android.app.role.SMS"
-        shortcut="s" />
+        androidprv:keycode="KEYCODE_S"
+        androidprv:modifierState="META" />
     <bookmark
         category="android.intent.category.APP_CALCULATOR"
-        shortcut="u" />
+        androidprv:keycode="KEYCODE_U"
+        androidprv:modifierState="META" />
 
     <bookmark
         role="android.app.role.BROWSER"
-        shortcut="b"
-        shift="true" />
+        androidprv:keycode="KEYCODE_B"
+        androidprv:modifierState="META|SHIFT" />
 
     <bookmark
         category="android.intent.category.APP_CONTACTS"
-        shortcut="c"
+        androidprv:keycode="KEYCODE_C"
         shift="true" />
 
     <bookmark
         package="com.test"
         class="com.test.BookmarkTest"
-        shortcut="j"
+        androidprv:keycode="KEYCODE_J"
         shift="true" />
 </bookmarks>
\ No newline at end of file
diff --git a/tests/Input/res/xml/bookmarks_legacy.xml b/tests/Input/res/xml/bookmarks_legacy.xml
new file mode 100644
index 0000000..8bacf49
--- /dev/null
+++ b/tests/Input/res/xml/bookmarks_legacy.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 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.
+  -->
+<bookmarks>
+    <!-- The key combinations for the following shortcuts are legacy way defining bookmarks and we
+         should prefer new way of defining bookmarks as shown in {@link bookmarks.xml} -->
+    <bookmark
+        role="android.app.role.BROWSER"
+        shortcut="b" />
+    <bookmark
+        category="android.intent.category.APP_CONTACTS"
+        shortcut="c" />
+    <bookmark
+        category="android.intent.category.APP_EMAIL"
+        shortcut="e" />
+    <bookmark
+        category="android.intent.category.APP_CALENDAR"
+        shortcut="k" />
+    <bookmark
+        category="android.intent.category.APP_MAPS"
+        shortcut="m" />
+    <bookmark
+        category="android.intent.category.APP_MUSIC"
+        shortcut="p" />
+    <bookmark
+        role="android.app.role.SMS"
+        shortcut="s" />
+    <bookmark
+        category="android.intent.category.APP_CALCULATOR"
+        shortcut="u" />
+
+    <bookmark
+        role="android.app.role.BROWSER"
+        shortcut="b"
+        shift="true" />
+
+    <bookmark
+        category="android.intent.category.APP_CONTACTS"
+        shortcut="c"
+        shift="true" />
+
+    <bookmark
+        package="com.test"
+        class="com.test.BookmarkTest"
+        shortcut="j"
+        shift="true" />
+</bookmarks>
\ No newline at end of file
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 09a686c..34350ab 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -115,13 +115,11 @@
     private lateinit var iInputManager: IInputManager
 
     @Mock
-    private lateinit var resources: Resources
-
-    @Mock
     private lateinit var packageManager: PackageManager
 
     private var currentPid = 0
     private lateinit var context: Context
+    private lateinit var resources: Resources
     private lateinit var keyGestureController: KeyGestureController
     private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
     private lateinit var testLooper: TestLooper
@@ -130,6 +128,7 @@
     @Before
     fun setup() {
         context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+        resources = Mockito.spy(context.resources)
         setupInputDevices()
         setupBehaviors()
         testLooper = TestLooper()
@@ -146,10 +145,6 @@
     private fun setupBehaviors() {
         Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1")
         Mockito.`when`(resources.getBoolean(R.bool.config_enableScreenshotChord)).thenReturn(true)
-        val testBookmarks: XmlResourceParser = context.resources.getXml(
-            com.android.test.input.R.xml.bookmarks
-        )
-        Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks)
         Mockito.`when`(context.resources).thenReturn(resources)
         Mockito.`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH))
             .thenReturn(true)
@@ -158,6 +153,11 @@
         Mockito.`when`(context.packageManager).thenReturn(packageManager)
     }
 
+    private fun setupBookmarks(bookmarkRes: Int) {
+        val testBookmarks: XmlResourceParser = context.resources.getXml(bookmarkRes)
+        Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks)
+    }
+
     private fun setupInputDevices() {
         val correctIm = context.getSystemService(InputManager::class.java)!!
         val virtualDevice = correctIm.getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD)!!
@@ -604,45 +604,6 @@
                 AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR)
             ),
             TestData(
-                "META + SHIFT + B -> Launch Default Browser",
-                intArrayOf(
-                    KeyEvent.KEYCODE_META_LEFT,
-                    KeyEvent.KEYCODE_SHIFT_LEFT,
-                    KeyEvent.KEYCODE_B
-                ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
-                intArrayOf(KeyEvent.KEYCODE_B),
-                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
-                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
-                AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
-            ),
-            TestData(
-                "META + SHIFT + C -> Launch Default Contacts",
-                intArrayOf(
-                    KeyEvent.KEYCODE_META_LEFT,
-                    KeyEvent.KEYCODE_SHIFT_LEFT,
-                    KeyEvent.KEYCODE_C
-                ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
-                intArrayOf(KeyEvent.KEYCODE_C),
-                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
-                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
-                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
-            ),
-            TestData(
-                "META + SHIFT + J -> Launch Target Activity",
-                intArrayOf(
-                    KeyEvent.KEYCODE_META_LEFT,
-                    KeyEvent.KEYCODE_SHIFT_LEFT,
-                    KeyEvent.KEYCODE_J
-                ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
-                intArrayOf(KeyEvent.KEYCODE_J),
-                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
-                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
-                AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
-            ),
-            TestData(
                 "META + CTRL + DEL -> Trigger Bug Report",
                 intArrayOf(
                     KeyEvent.KEYCODE_META_LEFT,
@@ -715,47 +676,47 @@
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + [ -> Resizes a task to fit the left half of the screen",
+                "META + [ -> Resizes a task to fit the left half of the screen",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_LEFT_BRACKET
                 ),
                 KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + ] -> Resizes a task to fit the right half of the screen",
+                "META + ] -> Resizes a task to fit the right half of the screen",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_RIGHT_BRACKET
                 ),
                 KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + '=' -> Maximizes a task to fit the screen",
+                "META + '=' -> Toggles maximization of a task to maximized and restore its bounds",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_EQUALS
                 ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
+                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_EQUALS),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "ALT + '-' -> Restores a task size to its previous bounds",
+                "META + '-' -> Minimizes a freeform task",
                 intArrayOf(
-                    KeyEvent.KEYCODE_ALT_LEFT,
+                    KeyEvent.KEYCODE_META_LEFT,
                     KeyEvent.KEYCODE_MINUS
                 ),
-                KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
+                KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW,
                 intArrayOf(KeyEvent.KEYCODE_MINUS),
-                KeyEvent.META_ALT_ON,
+                KeyEvent.META_META_ON,
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
@@ -866,6 +827,139 @@
     }
 
     @Keep
+    private fun bookmarkArguments(): Array<TestData> {
+        return arrayOf(
+            TestData(
+                "META + B -> Launch Default Browser",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_B),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_B),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
+            ),
+            TestData(
+                "META + C -> Launch Default Contacts",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_C),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
+            ),
+            TestData(
+                "META + E -> Launch Default Email",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_E),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_E),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_EMAIL)
+            ),
+            TestData(
+                "META + K -> Launch Default Calendar",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_K),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_K),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALENDAR)
+            ),
+            TestData(
+                "META + M -> Launch Default Maps",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_M),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_M),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MAPS)
+            ),
+            TestData(
+                "META + P -> Launch Default Music",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_P),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MUSIC)
+            ),
+            TestData(
+                "META + S -> Launch Default SMS",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_S),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_S),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_SMS)
+            ),
+            TestData(
+                "META + U -> Launch Default Calculator",
+                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_U),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_U),
+                KeyEvent.META_META_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR)
+            ),
+            TestData(
+                "META + SHIFT + B -> Launch Default Browser",
+                intArrayOf(
+                    KeyEvent.KEYCODE_META_LEFT,
+                    KeyEvent.KEYCODE_SHIFT_LEFT,
+                    KeyEvent.KEYCODE_B
+                ),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_B),
+                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER)
+            ),
+            TestData(
+                "META + SHIFT + C -> Launch Default Contacts",
+                intArrayOf(
+                    KeyEvent.KEYCODE_META_LEFT,
+                    KeyEvent.KEYCODE_SHIFT_LEFT,
+                    KeyEvent.KEYCODE_C
+                ),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_C),
+                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS)
+            ),
+            TestData(
+                "META + SHIFT + J -> Launch Target Activity",
+                intArrayOf(
+                    KeyEvent.KEYCODE_META_LEFT,
+                    KeyEvent.KEYCODE_SHIFT_LEFT,
+                    KeyEvent.KEYCODE_J
+                ),
+                KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION,
+                intArrayOf(KeyEvent.KEYCODE_J),
+                KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON,
+                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE),
+                AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest")
+            )
+        )
+    }
+
+    @Test
+    @Parameters(method = "bookmarkArguments")
+    fun testBookmarks(test: TestData) {
+        setupBookmarks(com.android.test.input.R.xml.bookmarks)
+        setupKeyGestureController()
+        testKeyGestureInternal(test)
+    }
+
+    @Test
+    @Parameters(method = "bookmarkArguments")
+    fun testBookmarksLegacy(test: TestData) {
+        setupBookmarks(com.android.test.input.R.xml.bookmarks_legacy)
+        setupKeyGestureController()
+        testKeyGestureInternal(test)
+    }
+
+    @Keep
     private fun systemKeysTestArguments(): Array<TestData> {
         return arrayOf(
             TestData(
diff --git a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 58fb4e1..938e2f8 100644
--- a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -19,6 +19,7 @@
 import android.animation.ValueAnimator
 import android.content.Context
 import android.content.ContextWrapper
+import android.content.res.Resources
 import android.graphics.Color
 import android.hardware.input.IKeyboardBacklightListener
 import android.hardware.input.IKeyboardBacklightState
@@ -28,11 +29,12 @@
 import android.os.test.TestLooper
 import android.platform.test.annotations.Presubmit
 import android.view.InputDevice
+import android.util.TypedValue
 import androidx.test.annotation.UiThreadTest
 import androidx.test.core.app.ApplicationProvider
+import com.android.internal.R
 import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL
 import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS
-import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS
 import com.android.test.input.MockInputManagerRule
 import java.io.FileNotFoundException
 import java.io.FileOutputStream
@@ -49,6 +51,7 @@
 import org.junit.Test
 import org.mockito.Mock
 import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.spy
@@ -94,6 +97,7 @@
         const val LIGHT_ID = 2
         const val SECOND_LIGHT_ID = 3
         const val MAX_BRIGHTNESS = 255
+        const val USER_INACTIVITY_THRESHOLD_MILLIS = 30000
     }
 
     @get:Rule
@@ -105,6 +109,8 @@
     private lateinit var native: NativeInputManagerService
     @Mock
     private lateinit var uEventManager: UEventManager
+    @Mock
+    private lateinit var resources: Resources
     private lateinit var keyboardBacklightController: KeyboardBacklightController
     private lateinit var context: Context
     private lateinit var dataStore: PersistentDataStore
@@ -117,6 +123,7 @@
     @Before
     fun setup() {
         context = spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+        `when`(context.resources).thenReturn(resources)
         dataStore = PersistentDataStore(object : PersistentDataStore.Injector() {
             override fun openRead(): InputStream? {
                 throw FileNotFoundException()
@@ -129,6 +136,7 @@
             override fun finishWrite(fos: FileOutputStream?, success: Boolean) {}
         })
         testLooper = TestLooper()
+        setupConfig()
         keyboardBacklightController = KeyboardBacklightController(context, native, dataStore,
                 testLooper.looper, FakeAnimatorFactory(), uEventManager)
         val inputManager = InputManager(context)
@@ -147,7 +155,31 @@
             sysfsNodeChanges++
         }
     }
-
+    private fun setupConfig() {
+        val brightnessValues = intArrayOf(100, 200, 0)
+        val decreaseThresholds = intArrayOf(-1, 900, 1900)
+        val increaseThresholds = intArrayOf(1000, 2000, -1)
+        `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightBrightnessValues))
+            .thenReturn(brightnessValues)
+        `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightDecreaseLuxThreshold))
+            .thenReturn(decreaseThresholds)
+        `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightIncreaseLuxThreshold))
+            .thenReturn(increaseThresholds)
+        `when`(resources.getInteger(R.integer.config_keyboardBacklightTimeoutMs))
+            .thenReturn(USER_INACTIVITY_THRESHOLD_MILLIS)
+        `when`(
+            resources.getValue(
+                eq(R.dimen.config_autoKeyboardBrightnessSmoothingConstant),
+                any(TypedValue::class.java),
+                anyBoolean()
+            )
+        ).then {
+            val args = it.arguments
+            val outValue = args[1] as TypedValue
+            outValue.data = java.lang.Float.floatToRawIntBits(1.0f)
+            Unit
+        }
+    }
     @Test
     fun testKeyboardBacklightIncrementDecrement() {
         KeyboardBacklightFlags(
@@ -365,7 +397,7 @@
                 lightColorMap[LIGHT_ID]
             )
 
-            testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000)
+            testLooper.moveTimeForward((USER_INACTIVITY_THRESHOLD_MILLIS + 1000).toLong())
             testLooper.dispatchNext()
             assertEquals(
                 "Keyboard backlight level should be turned off after inactivity",
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 91483eb..8be74eacc 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -37,7 +37,7 @@
         "truth",
     ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
         "true": [
-            "service-crashrecovery.impl",
+            "service-crashrecovery-pre-jarjar",
             "framework-crashrecovery.impl",
         ],
         default: [],
diff --git a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
index 2692e12..44641f7 100644
--- a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -57,6 +58,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
 
 import perfetto.protos.Protolog;
 import perfetto.protos.ProtologCommon;
@@ -858,6 +860,39 @@
                 .isEqualTo("This message should also be logged 567");
     }
 
+    @Test
+    public void enablesLogGroupAfterLoadingConfig() {
+        sProtoLog.stopLoggingToLogcat(
+                new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+        Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+
+        doAnswer((Answer<Void>) invocation -> {
+            // logToLogcat is still false before we laod the viewer config
+            Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+            return null;
+        }).when(sReader).unloadViewerConfig(any(), any());
+
+        sProtoLog.startLoggingToLogcat(
+                new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+        Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue();
+    }
+
+    @Test
+    public void disablesLogGroupBeforeUnloadingConfig() {
+        sProtoLog.startLoggingToLogcat(
+                new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+        Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue();
+
+        doAnswer((Answer<Void>) invocation -> {
+            // Already set logToLogcat to false by the time we unload the config
+            Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+            return null;
+        }).when(sReader).unloadViewerConfig(any(), any());
+        sProtoLog.stopLoggingToLogcat(
+                new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {});
+        Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse();
+    }
+
     private enum TestProtoLogGroup implements IProtoLogGroup {
         TEST_GROUP(true, true, false, "TEST_TAG");
 
diff --git a/tests/broadcasts/OWNERS b/tests/broadcasts/OWNERS
deleted file mode 100644
index d2e1f81..0000000
--- a/tests/broadcasts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 316181
-include platform/frameworks/base:/BROADCASTS_OWNERS
diff --git a/tests/broadcasts/unit/Android.bp b/tests/broadcasts/unit/Android.bp
deleted file mode 100644
index 47166a7..0000000
--- a/tests/broadcasts/unit/Android.bp
+++ /dev/null
@@ -1,45 +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 {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-    default_team: "trendy_team_framework_backstage_power",
-}
-
-android_test {
-    name: "BroadcastUnitTests",
-    srcs: ["src/**/*.java"],
-    defaults: [
-        "modules-utils-extended-mockito-rule-defaults",
-    ],
-    static_libs: [
-        "androidx.test.runner",
-        "androidx.test.rules",
-        "androidx.test.ext.junit",
-        "mockito-target-extended-minus-junit4",
-        "truth",
-        "flag-junit",
-        "android.app.flags-aconfig-java",
-    ],
-    certificate: "platform",
-    platform_apis: true,
-    test_suites: ["device-tests"],
-}
diff --git a/tests/broadcasts/unit/AndroidManifest.xml b/tests/broadcasts/unit/AndroidManifest.xml
deleted file mode 100644
index e9c5248..0000000
--- a/tests/broadcasts/unit/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2024 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.broadcasts.unit" >
-
-    <application android:debuggable="true">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.broadcasts.unit"
-            android:label="Broadcasts Unit Tests"/>
-</manifest>
\ No newline at end of file
diff --git a/tests/broadcasts/unit/AndroidTest.xml b/tests/broadcasts/unit/AndroidTest.xml
deleted file mode 100644
index b91e4783..0000000
--- a/tests/broadcasts/unit/AndroidTest.xml
+++ /dev/null
@@ -1,29 +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.
--->
-<configuration description="Runs Broadcasts tests">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-tag" value="BroadcastUnitTests" />
-
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="BroadcastUnitTests.apk" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.broadcasts.unit" />
-        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="hidden-api-checks" value="false"/>
-    </test>
-</configuration>
\ No newline at end of file
diff --git a/tests/broadcasts/unit/TEST_MAPPING b/tests/broadcasts/unit/TEST_MAPPING
deleted file mode 100644
index 8919fdc..0000000
--- a/tests/broadcasts/unit/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "presubmit": [
-        {
-            "name": "BroadcastUnitTests",
-            "options": [
-                {
-                    "exclude-annotation": "androidx.test.filters.FlakyTest"
-                },
-                {
-                    "exclude-annotation": "org.junit.Ignore"
-                }
-            ]
-        }
-    ]
-}
diff --git a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
deleted file mode 100644
index b7c412d..0000000
--- a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import static android.content.Intent.ACTION_BATTERY_CHANGED;
-import static android.content.Intent.ACTION_DEVICE_STORAGE_LOW;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.SystemProperties;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.util.ArrayMap;
-
-import androidx.annotation.GuardedBy;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.modules.utils.testing.ExtendedMockitoRule;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-@EnableFlags(Flags.FLAG_USE_STICKY_BCAST_CACHE)
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class BroadcastStickyCacheTest {
-    @ClassRule
-    public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
-    @Rule
-    public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
-
-    @Rule
-    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
-            .mockStatic(SystemProperties.class)
-            .build();
-
-    private static final String PROP_KEY_BATTERY_CHANGED = BroadcastStickyCache.getKey(
-            ACTION_BATTERY_CHANGED);
-
-    private final TestSystemProps mTestSystemProps = new TestSystemProps();
-
-    @Before
-    public void setUp() {
-        doAnswer(invocation -> {
-            final String name = invocation.getArgument(0);
-            final long value = Long.parseLong(invocation.getArgument(1));
-            mTestSystemProps.add(name, value);
-            return null;
-        }).when(() -> SystemProperties.set(anyString(), anyString()));
-        doAnswer(invocation -> {
-            final String name = invocation.getArgument(0);
-            final TestSystemProps.Handle testHandle = mTestSystemProps.query(name);
-            if (testHandle == null) {
-                return null;
-            }
-            final SystemProperties.Handle handle = Mockito.mock(SystemProperties.Handle.class);
-            doAnswer(handleInvocation -> testHandle.getLong(-1)).when(handle).getLong(anyLong());
-            return handle;
-        }).when(() -> SystemProperties.find(anyString()));
-    }
-
-    @After
-    public void tearDown() {
-        mTestSystemProps.clear();
-        BroadcastStickyCache.clearForTest();
-    }
-
-    @Test
-    public void testUseCache_nullFilter() {
-        assertThat(BroadcastStickyCache.useCache(null)).isEqualTo(false);
-    }
-
-    @Test
-    public void testUseCache_noActions() {
-        final IntentFilter filter = new IntentFilter();
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
-    }
-
-    @Test
-    public void testUseCache_multipleActions() {
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_DEVICE_STORAGE_LOW);
-        filter.addAction(ACTION_BATTERY_CHANGED);
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
-    }
-
-    @Test
-    public void testUseCache_valueNotSet() {
-        final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
-    }
-
-    @Test
-    public void testUseCache() {
-        final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
-        final Intent intent = new Intent(ACTION_BATTERY_CHANGED)
-                .putExtra(BatteryManager.EXTRA_LEVEL, 90);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        BroadcastStickyCache.add(filter, intent);
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true);
-    }
-
-    @Test
-    public void testUseCache_versionMismatch() {
-        final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
-        final Intent intent = new Intent(ACTION_BATTERY_CHANGED)
-                .putExtra(BatteryManager.EXTRA_LEVEL, 90);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        BroadcastStickyCache.add(filter, intent);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(false);
-    }
-
-    @Test
-    public void testAdd() {
-        final IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
-        Intent intent = new Intent(ACTION_BATTERY_CHANGED)
-                .putExtra(BatteryManager.EXTRA_LEVEL, 90);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        BroadcastStickyCache.add(filter, intent);
-        assertThat(BroadcastStickyCache.useCache(filter)).isEqualTo(true);
-        Intent actualIntent = BroadcastStickyCache.getIntentUnchecked(filter);
-        assertThat(actualIntent).isNotNull();
-        assertEquals(actualIntent, intent);
-
-        intent = new Intent(ACTION_BATTERY_CHANGED)
-                .putExtra(BatteryManager.EXTRA_LEVEL, 99);
-        BroadcastStickyCache.add(filter, intent);
-        actualIntent = BroadcastStickyCache.getIntentUnchecked(filter);
-        assertThat(actualIntent).isNotNull();
-        assertEquals(actualIntent, intent);
-    }
-
-    @Test
-    public void testIncrementVersion_propExists() {
-        SystemProperties.set(PROP_KEY_BATTERY_CHANGED, String.valueOf(100));
-
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(101);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(102);
-    }
-
-    @Test
-    public void testIncrementVersion_propNotExists() {
-        // Verify that the property doesn't exist
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(1);
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2);
-    }
-
-    @Test
-    public void testIncrementVersionIfExists_propExists() {
-        BroadcastStickyCache.incrementVersion(ACTION_BATTERY_CHANGED);
-
-        BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(2);
-        BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(3);
-    }
-
-    @Test
-    public void testIncrementVersionIfExists_propNotExists() {
-        // Verify that the property doesn't exist
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-
-        BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-        // Verify that property is not added as part of the querying.
-        BroadcastStickyCache.incrementVersionIfExists(ACTION_BATTERY_CHANGED);
-        assertThat(mTestSystemProps.get(PROP_KEY_BATTERY_CHANGED, -1 /* def */)).isEqualTo(-1);
-    }
-
-    private void assertEquals(Intent actualIntent, Intent expectedIntent) {
-        assertThat(actualIntent.getAction()).isEqualTo(expectedIntent.getAction());
-        assertEquals(actualIntent.getExtras(), expectedIntent.getExtras());
-    }
-
-    private void assertEquals(Bundle actualExtras, Bundle expectedExtras) {
-        assertWithMessage("Extras expected=%s, actual=%s", expectedExtras, actualExtras)
-                .that(actualExtras.kindofEquals(expectedExtras)).isTrue();
-    }
-
-    private static final class TestSystemProps {
-        @GuardedBy("mSysProps")
-        private final ArrayMap<String, Long> mSysProps = new ArrayMap<>();
-
-        public void add(String name, long value) {
-            synchronized (mSysProps) {
-                mSysProps.put(name, value);
-            }
-        }
-
-        public long get(String name, long defaultValue) {
-            synchronized (mSysProps) {
-                final int idx = mSysProps.indexOfKey(name);
-                return idx >= 0 ? mSysProps.valueAt(idx) : defaultValue;
-            }
-        }
-
-        public Handle query(String name) {
-            synchronized (mSysProps) {
-                return mSysProps.containsKey(name) ? new Handle(name) : null;
-            }
-        }
-
-        public void clear() {
-            synchronized (mSysProps) {
-                mSysProps.clear();
-            }
-        }
-
-        public class Handle {
-            private final String mName;
-
-            Handle(String name) {
-                mName = name;
-            }
-
-            public long getLong(long defaultValue) {
-                return get(mName, defaultValue);
-            }
-        }
-    }
-}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 1bef5f8..1d4adc4 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -207,14 +207,13 @@
   Value* dst_value = dst_config_value->value.get();
   Value* src_value = src_config_value->value.get();
 
-  CollisionResult collision_result;
-  if (overlay) {
-    collision_result =
-        ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool);
-  } else {
-    collision_result =
-        ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus());
-    if (collision_result == CollisionResult::kConflict) {
+  CollisionResult collision_result =
+      ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus());
+  if (collision_result == CollisionResult::kConflict) {
+    if (overlay) {
+      collision_result =
+          ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool);
+    } else {
       collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value);
     }
   }
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index f68ae2c..74a907f 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -309,7 +309,7 @@
      */
     @TestApi
     @NonNull
-    @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api")
+    @SuppressLint("UnflaggedApi") // Exempt: Test API for already shipped feature
     public BroadcastReceiver getBroadcastReceiver() {
         return mBroadcastReceiver;
     }