Merge "Add Merging Logic to Jank Processor" into main
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/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 8bd3ef4..637c726 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -36,10 +36,14 @@
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.UidObserver;
+import android.app.compat.CompatChanges;
 import android.app.job.JobInfo;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.Overridable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -132,6 +136,27 @@
         return (int) (val ^ (val >>> 32));
     }
 
+    /**
+     * When enabled this change id overrides the default quota policy enforcement to the jobs
+     * running in the foreground process state.
+     */
+    // TODO: b/379681266 - Might need some refactoring for a better app-compat strategy.
+    @VisibleForTesting
+    @ChangeId
+    @Disabled // Disabled by default
+    @Overridable // The change can be overridden in user build
+    static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS = 341201311L;
+
+    /**
+     * When enabled this change id overrides the default quota policy enforcement policy
+     * the jobs started when app was in the TOP state.
+     */
+    @VisibleForTesting
+    @ChangeId
+    @Disabled // Disabled by default
+    @Overridable // The change can be overridden in user build.
+    static final long OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS = 374323858L;
+
     @VisibleForTesting
     static class ExecutionStats {
         /**
@@ -622,7 +647,9 @@
         }
 
         final int uid = jobStatus.getSourceUid();
-        if (!Flags.enforceQuotaPolicyToTopStartedJobs() && mTopAppCache.get(uid)) {
+        if ((!Flags.enforceQuotaPolicyToTopStartedJobs()
+                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+                        uid)) && mTopAppCache.get(uid)) {
             if (DEBUG) {
                 Slog.d(TAG, jobStatus.toShortString() + " is top started job");
             }
@@ -659,7 +686,9 @@
                 timer.stopTrackingJob(jobStatus);
             }
         }
-        if (!Flags.enforceQuotaPolicyToTopStartedJobs()) {
+        if (!Flags.enforceQuotaPolicyToTopStartedJobs()
+                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+                        jobStatus.getSourceUid())) {
             mTopStartedJobs.remove(jobStatus);
         }
     }
@@ -772,7 +801,13 @@
 
     /** @return true if the job was started while the app was in the TOP state. */
     private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
-        return !Flags.enforceQuotaPolicyToTopStartedJobs() && mTopStartedJobs.contains(jobStatus);
+        if (!Flags.enforceQuotaPolicyToTopStartedJobs()
+                || CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+                        jobStatus.getSourceUid())) {
+            return mTopStartedJobs.contains(jobStatus);
+        }
+
+        return false;
     }
 
     /** Returns the maximum amount of time this job could run for. */
@@ -2634,9 +2669,13 @@
     }
 
     @VisibleForTesting
-    int getProcessStateQuotaFreeThreshold() {
-        return Flags.enforceQuotaPolicyToFgsJobs() ? ActivityManager.PROCESS_STATE_BOUND_TOP :
-                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    int getProcessStateQuotaFreeThreshold(int uid) {
+        if (Flags.enforceQuotaPolicyToFgsJobs()
+                && !CompatChanges.isChangeEnabled(OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS, uid)) {
+            return ActivityManager.PROCESS_STATE_BOUND_TOP;
+        }
+
+        return ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
     private class QcHandler extends Handler {
@@ -2776,7 +2815,7 @@
                                 isQuotaFree = true;
                             } else {
                                 final boolean reprocess;
-                                if (procState <= getProcessStateQuotaFreeThreshold()) {
+                                if (procState <= getProcessStateQuotaFreeThreshold(uid)) {
                                     reprocess = !mForegroundUids.get(uid);
                                     mForegroundUids.put(uid, true);
                                     isQuotaFree = true;
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 59dc314..5a7f2bd 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";
   }
 
@@ -2044,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
@@ -2120,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
@@ -2143,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
@@ -4601,6 +4614,7 @@
     method public void reportFullyDrawn();
     method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
     method public void requestFullscreenMode(int, @Nullable android.os.OutcomeReceiver<java.lang.Void,java.lang.Throwable>);
+    method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void requestOpenInBrowserEducation();
     method public final void requestPermissions(@NonNull String[], int);
     method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public final void requestPermissions(@NonNull String[], int, int);
     method public final void requestShowKeyboardShortcuts();
@@ -4626,7 +4640,6 @@
     method public void setInheritShowWhenLocked(boolean);
     method public void setIntent(android.content.Intent);
     method @FlaggedApi("android.security.content_uri_permission_apis") public void setIntent(@Nullable android.content.Intent, @Nullable android.app.ComponentCaller);
-    method @FlaggedApi("com.android.window.flags.enable_desktop_windowing_app_to_web_education") public final void setLimitSystemEducationDialogs(boolean);
     method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
@@ -5097,8 +5110,11 @@
   }
 
   public class AppOpsManager {
-    method @Deprecated public int checkOp(@NonNull String, int, @NonNull String);
-    method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+    method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String);
+    method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOp(@NonNull String, int, @NonNull String, @Nullable String);
+    method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
+    method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+    method @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int checkOpRawNoThrow(@NonNull String, int, @NonNull String, @Nullable String);
     method @Deprecated public void checkPackage(int, @NonNull String);
     method @Deprecated public void finishOp(@NonNull String, int, @NonNull String);
     method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String);
@@ -5127,10 +5143,10 @@
     method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
     method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
     method public void stopWatchingMode(@NonNull android.app.AppOpsManager.OnOpChangedListener);
-    method public int unsafeCheckOp(@NonNull String, int, @NonNull String);
-    method public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
-    method public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
-    method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
+    method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOp(@NonNull String, int, @NonNull String);
+    method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
+    method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
+    method @Deprecated @FlaggedApi("android.permission.flags.check_op_overload_api_enabled") public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
     field public static final int MODE_ALLOWED = 0; // 0x0
     field public static final int MODE_DEFAULT = 3; // 0x3
     field public static final int MODE_ERRORED = 2; // 0x2
@@ -6222,6 +6238,7 @@
   }
 
   public class KeyguardManager {
+    method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addDeviceLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.DeviceLockedStateListener);
     method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
     method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
     method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
@@ -6231,10 +6248,15 @@
     method public boolean isKeyguardLocked();
     method public boolean isKeyguardSecure();
     method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String);
+    method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeDeviceLockedStateListener(@NonNull android.app.KeyguardManager.DeviceLockedStateListener);
     method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeKeyguardLockedStateListener(@NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
     method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
   }
 
+  @FlaggedApi("android.app.device_unlock_listener") @java.lang.FunctionalInterface public static interface KeyguardManager.DeviceLockedStateListener {
+    method public void onDeviceLockedStateChanged(boolean);
+  }
+
   public abstract static class KeyguardManager.KeyguardDismissCallback {
     ctor public KeyguardManager.KeyguardDismissCallback();
     method public void onDismissCancelled();
@@ -13377,6 +13399,7 @@
     field public static final String FEATURE_BACKUP = "android.software.backup";
     field public static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     field public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
+    field @FlaggedApi("com.android.ranging.flags.ranging_cs_enabled") public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING = "android.hardware.bluetooth_le.channel_sounding";
     field public static final String FEATURE_CAMERA = "android.hardware.camera";
     field public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
     field public static final String FEATURE_CAMERA_AR = "android.hardware.camera.ar";
@@ -13568,6 +13591,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
@@ -13804,6 +13828,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();
@@ -17471,6 +17496,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);
@@ -17489,7 +17515,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);
@@ -21050,7 +21098,6 @@
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
-    method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
   }
 
@@ -21068,7 +21115,6 @@
     method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
     method public boolean isEnabled();
     method public boolean isRevoked();
-    method @FlaggedApi("android.view.inputmethod.verify_key_event") public boolean onShouldVerifyKeyEvent(@NonNull android.view.KeyEvent);
     method public void revokeSelf();
     method public void setEnabled(boolean);
   }
@@ -21521,6 +21567,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();
@@ -23143,7 +23190,6 @@
     method public boolean isVendor();
     field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_MEMORY_SAFE = 1; // 0x1
     field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_SANDBOXED = 0; // 0x0
-    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2; // 0x2
   }
 
   public static final class MediaCodecInfo.AudioCapabilities {
@@ -24034,7 +24080,6 @@
     field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
     field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_MEMORY_SAFE = 2; // 0x2
     field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_SANDBOXED = 1; // 0x1
-    field @FlaggedApi("android.media.codec.in_process_sw_audio_codec") public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 4; // 0x4
     field public static final String KEY_AAC_DRC_ALBUM_MODE = "aac-drc-album-mode";
     field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
     field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
@@ -27012,6 +27057,86 @@
 
 }
 
+package android.media.quality {
+
+  @FlaggedApi("android.media.tv.flags.media_quality_fw") public class MediaQualityContract {
+  }
+
+  public static final class MediaQualityContract.PictureQuality {
+    field public static final String PARAMETER_BRIGHTNESS = "brightness";
+    field public static final String PARAMETER_CONTRAST = "contrast";
+    field public static final String PARAMETER_SATURATION = "saturation";
+    field public static final String PARAMETER_SHARPNESS = "sharpness";
+  }
+
+  @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager {
+    method public void createPictureProfile(@NonNull android.media.quality.PictureProfile);
+    method @NonNull public java.util.List<android.media.quality.PictureProfile> getAvailablePictureProfiles();
+    method @NonNull public java.util.List<android.media.quality.ParamCapability> getParamCapabilities(@NonNull java.util.List<java.lang.String>);
+    method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String);
+    method public boolean isAutoPictureQualityEnabled();
+    method public boolean isSuperResolutionEnabled();
+    method public void registerPictureProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.PictureProfileCallback);
+    method public void removePictureProfile(@NonNull String);
+    method public void unregisterPictureProfileCallback(@NonNull android.media.quality.MediaQualityManager.PictureProfileCallback);
+    method public void updatePictureProfile(@NonNull String, @NonNull android.media.quality.PictureProfile);
+  }
+
+  public abstract static class MediaQualityManager.PictureProfileCallback {
+    ctor public MediaQualityManager.PictureProfileCallback();
+    method public void onError(int);
+    method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>);
+    method public void onPictureProfileAdded(@NonNull String, @NonNull android.media.quality.PictureProfile);
+    method public void onPictureProfileRemoved(@NonNull String, @NonNull android.media.quality.PictureProfile);
+    method public void onPictureProfileUpdated(@NonNull String, @NonNull android.media.quality.PictureProfile);
+  }
+
+  @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ParamCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.os.Bundle getCapabilities();
+    method @NonNull public String getParamName();
+    method public int getParamType();
+    method public boolean isSupported();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final String CAPABILITY_DEFAULT = "default";
+    field public static final String CAPABILITY_ENUM = "enum";
+    field public static final String CAPABILITY_MAX = "max";
+    field public static final String CAPABILITY_MIN = "min";
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.ParamCapability> CREATOR;
+    field public static final int TYPE_DOUBLE = 3; // 0x3
+    field public static final int TYPE_INT = 1; // 0x1
+    field public static final int TYPE_LONG = 2; // 0x2
+    field public static final int TYPE_STRING = 4; // 0x4
+  }
+
+  @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class PictureProfile implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getInputId();
+    method @NonNull public String getName();
+    method @Nullable public String getPackageName();
+    method @NonNull public android.os.PersistableBundle getParameters();
+    method @Nullable public String getProfileId();
+    method public int getProfileType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.PictureProfile> CREATOR;
+    field public static final int ERROR_DUPLICATE = 2; // 0x2
+    field public static final int ERROR_INVALID_ARGUMENT = 3; // 0x3
+    field public static final int ERROR_NOT_ALLOWLISTED = 4; // 0x4
+    field public static final int ERROR_NO_PERMISSION = 1; // 0x1
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_APPLICATION = 2; // 0x2
+    field public static final int TYPE_SYSTEM = 1; // 0x1
+  }
+
+  public static final class PictureProfile.Builder {
+    ctor public PictureProfile.Builder(@NonNull String);
+    ctor public PictureProfile.Builder(@NonNull android.media.quality.PictureProfile);
+    method @NonNull public android.media.quality.PictureProfile build();
+    method @NonNull public android.media.quality.PictureProfile.Builder setParameters(@NonNull android.os.PersistableBundle);
+  }
+
+}
+
 package android.media.session {
 
   public final class MediaController {
@@ -29876,6 +30001,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
   }
 
@@ -33682,7 +33808,7 @@
   }
 
   public interface IBinder {
-    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
     method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -34313,6 +34439,7 @@
     method public void finishBroadcast();
     method public Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") @Nullable public java.util.concurrent.Executor getExecutor();
     method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getFrozenCalleePolicy();
     method @FlaggedApi("android.os.binder_frozen_state_change_callback") public int getMaxQueueSize();
     method public Object getRegisteredCallbackCookie(int);
@@ -34333,6 +34460,7 @@
   @FlaggedApi("android.os.binder_frozen_state_change_callback") public static final class RemoteCallbackList.Builder<E extends android.os.IInterface> {
     ctor public RemoteCallbackList.Builder(int);
     method @NonNull public android.os.RemoteCallbackList<E> build();
+    method @NonNull public android.os.RemoteCallbackList.Builder setExecutor(@NonNull java.util.concurrent.Executor);
     method @NonNull public android.os.RemoteCallbackList.Builder setInterfaceDiedCallback(@NonNull android.os.RemoteCallbackList.Builder.InterfaceDiedCallback<E>);
     method @NonNull public android.os.RemoteCallbackList.Builder setMaxQueueSize(int);
   }
@@ -34712,8 +34840,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
@@ -34741,8 +34867,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 {
@@ -40737,6 +40865,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;
   }
@@ -40746,10 +40875,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
@@ -40758,6 +40889,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
@@ -40766,6 +40898,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
@@ -42051,6 +42184,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);
@@ -49736,6 +49870,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 {
   }
 
@@ -54907,6 +55049,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 {
@@ -56629,6 +56773,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;
   }
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 dcb4a40..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 {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fee53d6..14a6c8c 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";
@@ -101,6 +103,7 @@
     field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
     field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
     field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+    field @FlaggedApi("android.media.audio.concurrent_audio_record_bypass_permission") public static final String BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION = "android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION";
     field public static final String BYPASS_ROLE_QUALIFICATION = "android.permission.BYPASS_ROLE_QUALIFICATION";
     field public static final String CALL_AUDIO_INTERCEPTION = "android.permission.CALL_AUDIO_INTERCEPTION";
     field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
@@ -164,6 +167,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 +213,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";
@@ -225,6 +230,7 @@
     field public static final String MANAGE_ROTATION_RESOLVER = "android.permission.MANAGE_ROTATION_RESOLVER";
     field public static final String MANAGE_SAFETY_CENTER = "android.permission.MANAGE_SAFETY_CENTER";
     field public static final String MANAGE_SEARCH_UI = "android.permission.MANAGE_SEARCH_UI";
+    field @FlaggedApi("android.security.secure_lockdown") public static final String MANAGE_SECURE_LOCK_DEVICE = "android.permission.MANAGE_SECURE_LOCK_DEVICE";
     field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
     field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE";
     field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
@@ -304,6 +310,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 +535,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 +1344,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 +1942,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();
@@ -3860,6 +3871,7 @@
     field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume";
+    field @FlaggedApi("android.security.secure_lockdown") public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy";
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
     field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
@@ -4585,6 +4597,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 +5075,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 +5103,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 +5217,142 @@
     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();
+    method @Nullable public android.hardware.contexthub.HubServiceInfo getHubServiceInfo();
+  }
+
+  @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 @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection();
+    method @Nullable public String getTag();
+    method public int getVersion();
+  }
+
+  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 setServiceInfoCollection(@NonNull java.util.Collection<android.hardware.contexthub.HubServiceInfo>);
+    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 @NonNull public java.util.Collection<java.lang.String> getRequiredPermissions();
+    method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection();
+    method @Nullable public String getTag();
+    method public int getType();
+    method public int getVersion();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubEndpointInfo> CREATOR;
+    field public static final int TYPE_APP = 2; // 0x2
+    field public static final int TYPE_FRAMEWORK = 1; // 0x1
+    field public static final int TYPE_HUB_ENDPOINT = 5; // 0x5
+    field public static final int TYPE_NANOAPP = 4; // 0x4
+    field public static final int TYPE_NATIVE = 3; // 0x3
+  }
+
+  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 @Nullable public android.hardware.contexthub.HubServiceInfo getServiceInfo();
+    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 final class HubServiceInfo implements android.os.Parcelable {
+    ctor public HubServiceInfo(@NonNull String, int, int, int, @NonNull android.os.ParcelableHolder);
+    method public int describeContents();
+    method @NonNull public android.os.ParcelableHolder getExtendedInfo();
+    method public int getFormat();
+    method public int getMajorVersion();
+    method public int getMinorVersion();
+    method @NonNull public String getServiceDescriptor();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubServiceInfo> CREATOR;
+    field public static final int FORMAT_AIDL = 1; // 0x1
+    field public static final int FORMAT_CUSTOM = 0; // 0x0
+    field public static final int FORMAT_PW_RPC_PROTOBUF = 2; // 0x2
+  }
+
+  public static final class HubServiceInfo.Builder {
+    ctor public HubServiceInfo.Builder(@NonNull String, int, int, int);
+    method @NonNull public android.hardware.contexthub.HubServiceInfo build();
+    method @NonNull public android.hardware.contexthub.HubServiceInfo.Builder setExtendedInfo(@Nullable android.os.Parcelable);
+  }
+
+  @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, @Nullable android.hardware.contexthub.HubServiceInfo);
+    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 +5485,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 +6347,8 @@
     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 @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(@NonNull String);
     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 +6356,17 @@
     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 @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, @NonNull android.hardware.contexthub.HubServiceInfo);
     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 +6422,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
@@ -7958,6 +8151,25 @@
 
 }
 
+package android.media.quality {
+
+  @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager {
+    method @NonNull public java.util.List<java.lang.String> getPictureProfileAllowList();
+    method @NonNull public java.util.List<java.lang.String> getPictureProfilePackageNames();
+    method @NonNull public java.util.List<android.media.quality.PictureProfile> getPictureProfilesByPackage(@NonNull String);
+    method public void setAutoPictureQualityEnabled(boolean);
+    method public void setPictureProfileAllowList(@NonNull java.util.List<java.lang.String>);
+    method public void setSuperResolutionEnabled(boolean);
+  }
+
+  public static final class PictureProfile.Builder {
+    method @NonNull public android.media.quality.PictureProfile.Builder setInputId(@NonNull String);
+    method @NonNull public android.media.quality.PictureProfile.Builder setPackageName(@NonNull String);
+    method @NonNull public android.media.quality.PictureProfile.Builder setProfileType(int);
+  }
+
+}
+
 package android.media.session {
 
   public final class MediaSessionManager {
@@ -8250,18 +8462,96 @@
 
   @FlaggedApi("android.media.tv.flags.tif_extension_standardization") public final class TvInputServiceExtensionManager {
     method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public int registerExtensionIBinder(@NonNull String, @NonNull android.os.IBinder);
-    field public static final String IBROADCAST_TIME = "android.media.tv.extension.time.BroadcastTime";
+    field public static final String IANALOG_ATTRIBUTE_INTERFACE = "android.media.tv.extension.analog.IAnalogAttributeInterface";
+    field public static final String IANALOG_AUDIO_INFO = "android.media.tv.extension.signal.IAnalogAudioInfo";
+    field public static final String IAUDIO_SIGNAL_INFO = "android.media.tv.extension.signal.IAudioSignalInfo";
+    field public static final String IAUDIO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IAudioSignalInfoListener";
+    field public static final String IBROADCAST_TIME = "android.media.tv.extension.time.IBroadcastTime";
+    field public static final String ICAM_APP_INFO_LISTENER = "android.media.tv.extension.cam.ICamAppInfoListener";
     field public static final String ICAM_APP_INFO_SERVICE = "android.media.tv.extension.cam.ICamAppInfoService";
+    field public static final String ICAM_DRM_INFO_LISTENER = "android.media.tv.extension.cam.ICamDrmInfoListener";
+    field public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = "android.media.tv.extension.cam.ICamHostControlAskReleaseReplyCallback";
+    field public static final String ICAM_HOST_CONTROL_INFO_LISTENER = "android.media.tv.extension.cam.ICamHostControlInfoListener";
+    field public static final String ICAM_HOST_CONTROL_SERVICE = "android.media.tv.extension.cam.ICamHostControlService";
+    field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlag";
+    field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlagListener";
+    field public static final String ICAM_INFO_LISTENER = "android.media.tv.extension.cam.ICamInfoListener";
+    field public static final String ICAM_MONITORING_SERVICE = "android.media.tv.extension.cam.ICamMonitoringService";
+    field public static final String ICAM_PIN_CAPABILITY_LISTENER = "android.media.tv.extension.cam.ICamPinCapabilityListener";
+    field public static final String ICAM_PIN_SERVICE = "android.media.tv.extension.cam.ICamPinService";
+    field public static final String ICAM_PIN_STATUS_LISTENER = "android.media.tv.extension.cam.ICamPinStatusListener";
+    field public static final String ICAM_PROFILE_INTERFACE = "android.media.tv.extension.cam.ICamProfileInterface";
+    field public static final String ICHANNEL_LIST_TRANSFER = "android.media.tv.extension.servicedb.IChannelListTransfer";
+    field public static final String ICHANNEL_TUNED_INTERFACE = "android.media.tv.extension.tune.IChannelTunedInterface";
+    field public static final String ICHANNEL_TUNED_LISTENER = "android.media.tv.extension.tune.IChannelTunedListener";
+    field public static final String ICI_OPERATOR_INTERFACE = "android.media.tv.extension.cam.ICiOperatorInterface";
+    field public static final String ICI_OPERATOR_LISTENER = "android.media.tv.extension.cam.ICiOperatorListener";
     field public static final String ICLIENT_TOKEN = "android.media.tv.extension.clienttoken.IClientToken";
+    field public static final String ICONTENT_CONTROL_SERVICE = "android.media.tv.extension.cam.IContentControlService";
     field public static final String IDATA_SERVICE_SIGNAL_INFO = "android.media.tv.extension.teletext.IDataServiceSignalInfo";
+    field public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = "android.media.tv.extension.teletext.IDataServiceSignalInfoListener";
+    field public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IDeleteRecordedContentsCallback";
+    field public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = "android.media.tv.extension.rating.IDownloadableRatingTableMonitor";
+    field public static final String IENTER_MENU_ERROR_CALLBACK = "android.media.tv.extension.cam.IEnterMenuErrorCallback";
+    field public static final String IEVENT_DOWNLOAD = "android.media.tv.extension.event.IEventDownload";
+    field public static final String IEVENT_DOWNLOAD_LISTENER = "android.media.tv.extension.event.IEventDownloadListener";
+    field public static final String IEVENT_DOWNLOAD_SESSION = "android.media.tv.extension.event.IEventDownloadSession";
     field public static final String IEVENT_MONITOR = "android.media.tv.extension.event.IEventMonitor";
+    field public static final String IEVENT_MONITOR_LISTENER = "android.media.tv.extension.event.IEventMonitorListener";
+    field public static final String IFAVORITE_NETWORK = "android.media.tv.extension.scan.IFavoriteNetwork";
+    field public static final String IFAVORITE_NETWORK_LISTENER = "android.media.tv.extension.scan.IFavoriteNetworkListener";
+    field public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback";
+    field public static final String IHDMI_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IHdmiSignalInfoListener";
     field public static final String IHDMI_SIGNAL_INTERFACE = "android.media.tv.extension.signal.IHdmiSignalInterface";
+    field public static final String IHDPLUS_INFO = "android.media.tv.extension.scan.IHDPlusInfo";
+    field public static final String ILCNV2_CHANNEL_LIST = "android.media.tv.extension.scan.ILcnV2ChannelList";
+    field public static final String ILCNV2_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.ILcnV2ChannelListListener";
+    field public static final String ILCN_CONFLICT = "android.media.tv.extension.scan.ILcnConflict";
+    field public static final String ILCN_CONFLICT_LISTENER = "android.media.tv.extension.scan.ILcnConflictListener";
+    field public static final String IMMI_INTERFACE = "android.media.tv.extension.cam.IMmiInterface";
+    field public static final String IMMI_SESSION = "android.media.tv.extension.cam.IMmiSession";
+    field public static final String IMMI_STATUS_CALLBACK = "android.media.tv.extension.cam.IMmiStatusCallback";
+    field public static final String IMUX_TUNE = "android.media.tv.extension.tune.IMuxTune";
+    field public static final String IMUX_TUNE_SESSION = "android.media.tv.extension.tune.IMuxTuneSession";
     field public static final String IOAD_UPDATE_INTERFACE = "android.media.tv.extension.oad.IOadUpdateInterface";
+    field public static final String IOPERATOR_DETECTION = "android.media.tv.extension.scan.IOperatorDetection";
+    field public static final String IOPERATOR_DETECTION_LISTENER = "android.media.tv.extension.scan.IOperatorDetectionListener";
+    field public static final String IPMT_RATING_INTERFACE = "android.media.tv.extension.rating.IPmtRatingInterface";
+    field public static final String IPMT_RATING_LISTENER = "android.media.tv.extension.rating.IPmtRatingListener";
+    field public static final String IPROGRAM_INFO = "android.media.tv.extension.rating.IProgramInfo";
+    field public static final String IPROGRAM_INFO_LISTENER = "android.media.tv.extension.rating.IProgramInfoListener";
     field public static final String IRATING_INTERFACE = "android.media.tv.extension.rating.IRatingInterface";
     field public static final String IRECORDED_CONTENTS = "android.media.tv.extension.pvr.IRecordedContents";
+    field public static final String IREGION_CHANNEL_LIST = "android.media.tv.extension.scan.IRegionChannelList";
+    field public static final String IREGION_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.IRegionChannelListListener";
+    field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdate";
+    field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener";
     field public static final String ISCAN_INTERFACE = "android.media.tv.extension.scan.IScanInterface";
+    field public static final String ISCAN_LISTENER = "android.media.tv.extension.scan.IScanListener";
+    field public static final String ISCAN_SAT_SEARCH = "android.media.tv.extension.scan.IScanSatSearch";
+    field public static final String ISCAN_SESSION = "android.media.tv.extension.scan.IScanSession";
     field public static final String ISCREEN_MODE_SETTINGS = "android.media.tv.extension.screenmode.IScreenModeSettings";
+    field public static final String ISERVICE_LIST = "android.media.tv.extension.servicedb.IServiceList";
+    field public static final String ISERVICE_LIST_EDIT = "android.media.tv.extension.servicedb.IServiceListEdit";
     field public static final String ISERVICE_LIST_EDIT_LISTENER = "android.media.tv.extension.servicedb.IServiceListEditListener";
+    field public static final String ISERVICE_LIST_EXPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListExportListener";
+    field public static final String ISERVICE_LIST_EXPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListExportSession";
+    field public static final String ISERVICE_LIST_IMPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListImportListener";
+    field public static final String ISERVICE_LIST_IMPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListImportSession";
+    field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = "android.media.tv.extension.servicedb.IServiceListSetChannelListListener";
+    field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = "android.media.tv.extension.servicedb.IServiceListSetChannelListSession";
+    field public static final String ISERVICE_LIST_TRANSFER_INTERFACE = "android.media.tv.extension.servicedb.IServiceListTransferInterface";
+    field public static final String ITARGET_REGION = "android.media.tv.extension.scan.ITargetRegion";
+    field public static final String ITARGET_REGION_LISTENER = "android.media.tv.extension.scan.ITargetRegionListener";
+    field public static final String ITELETEXT_PAGE_SUB_CODE = "android.media.tv.extension.teletext.ITeletextPageSubCode";
+    field public static final String ITKGS_INFO = "android.media.tv.extension.scan.ITkgsInfo";
+    field public static final String ITKGS_INFO_LISTENER = "android.media.tv.extension.scan.ITkgsInfoListener";
+    field public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = "android.media.tv.extension.signal.ITunerFrontendSignalInfoInterface";
+    field public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.ITunerFrontendSignalInfoListener";
+    field public static final String IVBI_RATING_INTERFACE = "android.media.tv.extension.rating.IVbiRatingInterface";
+    field public static final String IVBI_RATING_LISTENER = "android.media.tv.extension.rating.IVbiRatingListener";
+    field public static final String IVIDEO_SIGNAL_INFO = "android.media.tv.extension.signal.IVideoSignalInfo";
+    field public static final String IVIDEO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IVideoSignalInfoListener";
     field public static final int REGISTER_FAIL_IMPLEMENTATION_NOT_STANDARDIZED = 2; // 0x2
     field public static final int REGISTER_FAIL_NAME_NOT_STANDARDIZED = 1; // 0x1
     field public static final int REGISTER_FAIL_REMOTE_EXCEPTION = 3; // 0x3
@@ -12571,6 +12861,59 @@
 
 }
 
+package android.security.authenticationpolicy {
+
+  @FlaggedApi("android.security.secure_lockdown") public final class AuthenticationPolicyManager {
+    method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int disableSecureLockDevice(@NonNull android.security.authenticationpolicy.DisableSecureLockDeviceParams);
+    method @FlaggedApi("android.security.secure_lockdown") @RequiresPermission(android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE) public int enableSecureLockDevice(@NonNull android.security.authenticationpolicy.EnableSecureLockDeviceParams);
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_ALREADY_ENABLED = 6; // 0x6
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5; // 0x5
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_INVALID_PARAMS = 3; // 0x3
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4; // 0x4
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("android.security.secure_lockdown") public static final int ERROR_UNSUPPORTED = 2; // 0x2
+    field @FlaggedApi("android.security.secure_lockdown") public static final int SUCCESS = 1; // 0x1
+  }
+
+  @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable {
+    ctor public DisableSecureLockDeviceParams(@NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR;
+  }
+
+  @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable {
+    ctor public EnableSecureLockDeviceParams(@NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR;
+  }
+
+}
+
+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();
+  }
+
+}
+
 package android.security.keystore {
 
   public class AndroidKeyStoreProvider extends java.security.Provider {
@@ -14970,6 +15313,32 @@
     method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCellularIdentifier();
+    method public int getNasProtocolMessage();
+    method @NonNull public String getPlmn();
+    method public boolean isEmergency();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CELLULAR_IDENTIFIER_IMEI = 2; // 0x2
+    field public static final int CELLULAR_IDENTIFIER_IMSI = 1; // 0x1
+    field public static final int CELLULAR_IDENTIFIER_SUCI = 3; // 0x3
+    field public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellularIdentifierDisclosure> CREATOR;
+    field public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1; // 0x1
+    field public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6; // 0x6
+    field public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9; // 0x9
+    field public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10; // 0xa
+    field public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8; // 0x8
+    field public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3; // 0x3
+    field public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2; // 0x2
+    field public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11; // 0xb
+    field public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5; // 0x5
+    field public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7; // 0x7
+    field public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4; // 0x4
+    field public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0; // 0x0
+  }
+
   public final class DataFailCause {
     field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
   }
@@ -15421,6 +15790,75 @@
     field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConnectionEvent();
+    method public int getEncryption();
+    method public int getIntegrity();
+    method public boolean isUnprotectedEmergency();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11; // 0xb
+    field public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5; // 0x5
+    field public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2; // 0x2
+    field public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0; // 0x0
+    field public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10; // 0xa
+    field public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4; // 0x4
+    field public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3; // 0x3
+    field public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1; // 0x1
+    field public static final int CONNECTION_EVENT_VOLTE_RTP = 8; // 0x8
+    field public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9; // 0x9
+    field public static final int CONNECTION_EVENT_VOLTE_SIP = 6; // 0x6
+    field public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7; // 0x7
+    field public static final int CONNECTION_EVENT_VONR_RTP = 14; // 0xe
+    field public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15; // 0xf
+    field public static final int CONNECTION_EVENT_VONR_SIP = 12; // 0xc
+    field public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13; // 0xd
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SecurityAlgorithmUpdate> CREATOR;
+    field public static final int SECURITY_ALGORITHM_A50 = 0; // 0x0
+    field public static final int SECURITY_ALGORITHM_A51 = 1; // 0x1
+    field public static final int SECURITY_ALGORITHM_A52 = 2; // 0x2
+    field public static final int SECURITY_ALGORITHM_A53 = 3; // 0x3
+    field public static final int SECURITY_ALGORITHM_A54 = 4; // 0x4
+    field public static final int SECURITY_ALGORITHM_AES_CBC = 71; // 0x47
+    field public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73; // 0x49
+    field public static final int SECURITY_ALGORITHM_AES_GCM = 69; // 0x45
+    field public static final int SECURITY_ALGORITHM_AES_GMAC = 70; // 0x46
+    field public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101; // 0x65
+    field public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72; // 0x48
+    field public static final int SECURITY_ALGORITHM_EEA0 = 41; // 0x29
+    field public static final int SECURITY_ALGORITHM_EEA1 = 42; // 0x2a
+    field public static final int SECURITY_ALGORITHM_EEA2 = 43; // 0x2b
+    field public static final int SECURITY_ALGORITHM_EEA3 = 44; // 0x2c
+    field public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100; // 0x64
+    field public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99; // 0x63
+    field public static final int SECURITY_ALGORITHM_GEA0 = 14; // 0xe
+    field public static final int SECURITY_ALGORITHM_GEA1 = 15; // 0xf
+    field public static final int SECURITY_ALGORITHM_GEA2 = 16; // 0x10
+    field public static final int SECURITY_ALGORITHM_GEA3 = 17; // 0x11
+    field public static final int SECURITY_ALGORITHM_GEA4 = 18; // 0x12
+    field public static final int SECURITY_ALGORITHM_GEA5 = 19; // 0x13
+    field public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75; // 0x4b
+    field public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74; // 0x4a
+    field public static final int SECURITY_ALGORITHM_IMS_NULL = 67; // 0x43
+    field public static final int SECURITY_ALGORITHM_NEA0 = 55; // 0x37
+    field public static final int SECURITY_ALGORITHM_NEA1 = 56; // 0x38
+    field public static final int SECURITY_ALGORITHM_NEA2 = 57; // 0x39
+    field public static final int SECURITY_ALGORITHM_NEA3 = 58; // 0x3a
+    field public static final int SECURITY_ALGORITHM_ORYX = 124; // 0x7c
+    field public static final int SECURITY_ALGORITHM_OTHER = 114; // 0x72
+    field public static final int SECURITY_ALGORITHM_RTP = 85; // 0x55
+    field public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66; // 0x42
+    field public static final int SECURITY_ALGORITHM_SIP_NULL = 68; // 0x44
+    field public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87; // 0x57
+    field public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88; // 0x58
+    field public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89; // 0x59
+    field public static final int SECURITY_ALGORITHM_SRTP_NULL = 86; // 0x56
+    field public static final int SECURITY_ALGORITHM_UEA0 = 29; // 0x1d
+    field public static final int SECURITY_ALGORITHM_UEA1 = 30; // 0x1e
+    field public static final int SECURITY_ALGORITHM_UEA2 = 31; // 0x1f
+    field public static final int SECURITY_ALGORITHM_UNKNOWN = 113; // 0x71
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
@@ -15645,6 +16083,7 @@
     field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
     field public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
     field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+    field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47; // 0x2f
     field @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
     field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
     field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
@@ -15669,6 +16108,7 @@
     field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
     field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+    field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46; // 0x2e
     field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
     field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
     field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
@@ -15687,6 +16127,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>);
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public static interface TelephonyCallback.CellularIdentifierDisclosedListener {
+    method public void onCellularIdentifierDisclosedChanged(@NonNull android.telephony.CellularIdentifierDisclosure);
+  }
+
   public static interface TelephonyCallback.DataEnabledListener {
     method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
   }
@@ -15725,6 +16169,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public static interface TelephonyCallback.SecurityAlgorithmsListener {
+    method public void onSecurityAlgorithmsChanged(@NonNull android.telephony.SecurityAlgorithmUpdate);
+  }
+
   @FlaggedApi("com.android.internal.telephony.flags.simultaneous_calling_indications") public static interface TelephonyCallback.SimultaneousCellularCallingSupportListener {
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSimultaneousCellularCallingSubscriptionsChanged(@NonNull java.util.Set<java.lang.Integer>);
   }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1192713..ad1d937 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1805,6 +1805,7 @@
     method @RequiresPermission(android.Manifest.permission.REMAP_MODIFIER_KEYS) public void remapModifierKey(int, int);
     method @FlaggedApi("com.android.input.flags.device_associations") @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByDescriptor(@NonNull String);
     method @RequiresPermission("android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY") public void removeUniqueIdAssociationByPort(@NonNull String);
+    method public void resetLockedModifierState();
     field public static final long BLOCK_UNTRUSTED_TOUCHES = 158002302L; // 0x96aec7eL
   }
 
@@ -2318,7 +2319,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);
   }
@@ -3240,6 +3241,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);
@@ -3251,6 +3253,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);
@@ -3393,6 +3399,10 @@
     ctor public BarringInfo.BarringServiceInfo(int, boolean, int, int);
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable {
+    ctor public CellularIdentifierDisclosure(int, int, @NonNull String, boolean);
+  }
+
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
     field public static final String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
   }
@@ -3420,6 +3430,10 @@
     ctor @Deprecated public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int);
   }
 
+  @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable {
+    ctor public SecurityAlgorithmUpdate(int, int, int, boolean);
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
     method public int getDataNetworkType();
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/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/Activity.java b/core/java/android/app/Activity.java
index 419eb7d..38aea64 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1270,27 +1270,22 @@
     }
 
     /**
-     * To make users aware of system features such as the app header menu and its various
-     * functionalities, educational dialogs are shown to demonstrate how to find and utilize these
-     * features. Using this method, an activity can specify if it wants these educational dialogs to
-     * be shown. When set to {@code true}, these dialogs are not completely blocked; however, the
-     * system will be notified that they should not be shown unless necessary. If this API is not
-     * called, the system's educational dialogs are not limited by default.
+     * Requests to show the “Open in browser” education. “Open in browser” is a feature
+     * within the app header that allows users to switch from an app to the web. The feature
+     * is made available when an application is opened by a user clicking a link or when a
+     * link is provided by an application. Links can be provided by utilizing
+     * {@link AssistContent#EXTRA_AUTHENTICATING_USER_WEB_URI} or
+     * {@link AssistContent#setWebUri}.
      *
-     * <p>This method can be utilized when activities have states where showing an
-     * educational dialog would be disruptive to the user. For example, if a game application is
-     * expecting prompt user input, this method can be used to limit educational dialogs such as the
-     * dialogs that showcase the app header's features which, in this instance, would disrupt the
-     * user's experience if shown.</p>
-     *
-     * <p>Note that educational dialogs may be shown soon after this activity is launched, so
-     * this method must be called early if the intent is to limit the dialogs from the start.</p>
+     * <p>This method should be utilized when an activity wants to nudge the user to switch
+     * to the web application in cases where the web may provide the user with a better
+     * experience. Note that this method does not guarantee that the education will be shown.</p>
      */
     @FlaggedApi(com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION)
-    public final void setLimitSystemEducationDialogs(boolean limitSystemEducationDialogs) {
+    public final void requestOpenInBrowserEducation() {
         try {
             ActivityTaskManager
-                  .getService().setLimitSystemEducationDialogs(mToken, limitSystemEducationDialogs);
+                  .getService().requestOpenInBrowserEducation(mToken);
         } catch (RemoteException e) {
             // Empty
         }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8b37dbd..3476578 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
@@ -8903,12 +8934,21 @@
     }
 
     /**
-     * Do a quick check for whether an application might be able to perform an operation.
-     * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
-     * String, String)} or {@link #startOp(String, int, String, String, String)} for your actual
-     * security checks. This function can just be used for a quick check to see if an operation has
-     * been disabled for the application, as an early reject of some work.  This does not modify the
-     * time stamp or other data about the operation.
+     * Check whether an application might be able to perform an operation.
+     * <p>
+     * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+     * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+     * String)} or {@link #startOp(String, int, String, String, String)} for your actual security
+     * checks. This function can just be used for a quick check to see if an operation has been
+     * disabled for the application, as an early reject of some work.
+     * <p>
+     * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, this
+     * is no longer an unsafe check, and it does the same security check as {@link #noteOp(String,
+     * int, String, String, String)} and {@link #startOp(String, int, String, String, String)}.
+     * However, it's preferred to use {@link #checkOp(String, int, String)}, since the word "unsafe"
+     * in the name of this API is no longer accurate.
+     * <p>
+     * This API does not modify the time stamp or other data about the operation.
      *
      * @param op The operation to check.  One of the OPSTR_* constants.
      * @param uid The user id of the application attempting to perform the operation.
@@ -8917,31 +8957,108 @@
      * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
+     *
+     * @deprecated Use {@link #checkOp(String, int, String)}
      */
+    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOp(strOpToOp(op), uid, packageName);
     }
 
     /**
-     * @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}.
+     * Check whether an application can perform an operation.
+     * <p>
+     * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+     * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+     * String)} or {@link #startOp(String, int, String, String, String)} for your actual security
+     * checks. This function can just be used for a quick check to see if an operation has been
+     * disabled for the application, as an early reject of some work.
+     * <p>
+     * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it
+     * does the same security check as {@link #noteOp(String, int, String, String, String)} and
+     * {@link #startOp(String, int, String, String, String)}, and should be preferred to use.
+     * <p>
+     * This API does not modify the time stamp or other data about the operation.
+     *
+     * @param op The operation to check. One of the OPSTR_* constants.
+     * @param uid The uid of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+     * causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
      */
-    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int checkOp(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOp(strOpToOp(op), uid, packageName);
     }
 
     /**
-     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
-     * returns {@link #MODE_ERRORED}.
+     * Like {@link #unsafeCheckOp(String, int, String)} but instead of throwing a
+     * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+     *
+     * @deprecated Use {@link #checkOpNoThrow(String, int, String)}
      */
+    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOpNoThrow(strOpToOp(op), uid, packageName);
     }
 
     /**
-     * @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}.
+     * Check whether an application can perform an operation. It does the same security check as
+     * {@link #noteOp(String, int, String, String, String)} and {@link #startOp(String, int, String,
+     * String, String)}, but does not modify the time stamp or other data about the operation.
+     *
+     * @param op The operation to check. One of the OPSTR_* constants.
+     * @param uid The uid of the application attempting to perform the operation.
+     * @param packageName The name of the application attempting to perform the operation.
+     * @param attributionTag The {@link Context#createAttributionContext attribution tag} of the
+     *                      calling context or {@code null} for default attribution
+     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
+     * if it is not allowed and should be silently ignored (without causing the app to crash).
+     * @throws SecurityException If the app has been configured to crash on this op.
      */
-    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+    public int checkOp(@NonNull String op, int uid, @NonNull String packageName,
+            @Nullable String attributionTag) {
+        int mode = checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+                Context.DEVICE_ID_DEFAULT);
+        if (mode == MODE_ERRORED) {
+            throw new SecurityException(buildSecurityExceptionMsg(strOpToOp(op), uid, packageName));
+        }
+        return mode;
+    }
+
+    /**
+     * Like {@link #checkOp(String, int, String, String)} but instead of throwing a
+     * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+     */
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+    public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
+            @Nullable String attributionTag) {
+        return checkOpNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+                Context.DEVICE_ID_DEFAULT);
+    }
+
+    /**
+     * Like {@link #checkOp(String, int, String, String)} but returns the <em>raw</em> mode
+     * associated with the op. Does not throw a security exception, does not translate
+     * {@link #MODE_FOREGROUND}.
+     */
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
+    public int checkOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName,
+            @Nullable String attributionTag) {
+        return checkOpRawNoThrow(strOpToOp(op), uid, packageName, attributionTag,
+                Context.DEVICE_ID_DEFAULT);
+    }
+
+    /**
+     * Like {@link #checkOp(String, int, String)} but instead of throwing a
+     * {@link SecurityException} it returns {@link #MODE_ERRORED}.
+     */
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOpNoThrow(strOpToOp(op), uid, packageName);
     }
@@ -8949,16 +9066,23 @@
     /**
      * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
      * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+     *
+     * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead
      */
+    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
         return unsafeCheckOpRawNoThrow(op, uid, packageName);
     }
 
     /**
-     * Like {@link #unsafeCheckOpNoThrow(String, int, String)} but returns the <em>raw</em>
-     * mode associated with the op. Does not throw a security exception, does not translate
-     * {@link #MODE_FOREGROUND}.
+     * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
+     * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+     *
+     * @deprecated Use {@link #checkOpRawNoThrow(String, int, String, String)} instead
      */
+    @Deprecated
+    @FlaggedApi(android.permission.flags.Flags.FLAG_CHECK_OP_OVERLOAD_API_ENABLED)
     public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName);
     }
@@ -8969,8 +9093,9 @@
      * @hide
      */
     public int unsafeCheckOpRawNoThrow(int op, @NonNull AttributionSource attributionSource) {
-        return unsafeCheckOpRawNoThrow(op, attributionSource.getUid(),
-                attributionSource.getPackageName(), attributionSource.getDeviceId());
+        return checkOpRawNoThrow(op, attributionSource.getUid(),
+                attributionSource.getPackageName(), attributionSource.getAttributionTag(),
+                attributionSource.getDeviceId());
     }
 
     /**
@@ -8991,20 +9116,20 @@
      * @hide
      */
     public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
-        return unsafeCheckOpRawNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT);
+        return checkOpRawNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
     }
 
-    private int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName,
-            int virtualDeviceId) {
+    private int checkOpRawNoThrow(int op, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, int virtualDeviceId) {
         try {
             int mode;
             if (isAppOpModeCachingEnabled(op)) {
                 mode = sAppOpModeCache.query(
-                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null,
+                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
                                 "unsafeCheckOpRawNoThrow"));
             } else {
                 mode = mService.checkOperationRawForDevice(
-                        op, uid, packageName, null, virtualDeviceId);
+                        op, uid, packageName, attributionTag, virtualDeviceId);
             }
             return mode;
         } catch (RemoteException e) {
@@ -9403,10 +9528,12 @@
     }
 
     /**
-     * Do a quick check for whether an application might be able to perform an operation.
-     * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
-     * String, String)} or {@link #startOp(int, int, String, boolean, String, String)} for your
-     * actual security checks, which also ensure that the given uid and package name are consistent.
+     * Check whether an application can perform an operation.
+     * <p>
+     * For platform versions before {@link android.os.Build.VERSION_CODES#BAKLAVA}, this is
+     * <em>not</em> a security check; you must use {@link #noteOp(String, int, String, String,
+     * String)} or {@link #startOp(int, int, String, boolean, String, String)} for your actual
+     * security checks, which also ensure that the given uid and package name are consistent.
      * This function can just be used for a quick check to see if an operation has been disabled for
      * the application, as an early reject of some work.  This does not modify the time stamp or
      * other data about the operation.
@@ -9422,6 +9549,13 @@
      *     as {@link #MODE_ALLOWED}.</li>
      * </ul>
      *
+     * <p>
+     * For platform versions equal to or after {@link android.os.Build.VERSION_CODES#BAKLAVA}, it
+     * does the same security check as {@link #noteOp(String, int, String, String, String)} and
+     * {@link #startOp(String, int, String, String, String)}.
+     * <p>
+     * This API does not modify the time stamp or other data about the operation.
+     *
      * @param op The operation to check.  One of the OP_* constants.
      * @param uid The user id of the application attempting to perform the operation.
      * @param packageName The name of the application attempting to perform the operation.
@@ -9433,29 +9567,11 @@
      */
     @UnsupportedAppUsage
     public int checkOp(int op, int uid, String packageName) {
-        try {
-            int mode;
-            if (isAppOpModeCachingEnabled(op)) {
-                mode = sAppOpModeCache.query(
-                        new AppOpModeQuery(op, uid, packageName, Context.DEVICE_ID_DEFAULT, null,
-                                "checkOp"));
-                if (mode == MODE_FOREGROUND) {
-                    // We only cache raw mode. If the mode is FOREGROUND, we need another binder
-                    // call to fetch translated value based on the process state.
-                    mode = mService.checkOperationForDevice(op, uid, packageName,
-                            Context.DEVICE_ID_DEFAULT);
-                }
-            } else {
-                mode = mService.checkOperationForDevice(op, uid, packageName,
-                        Context.DEVICE_ID_DEFAULT);
-            }
-            if (mode == MODE_ERRORED) {
-                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
-            }
-            return mode;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+        int mode = checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
+        if (mode == MODE_ERRORED) {
+            throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
         }
+        return mode;
     }
 
     /**
@@ -9468,7 +9584,7 @@
      */
     public int checkOpNoThrow(int op, AttributionSource attributionSource) {
         return checkOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
-                attributionSource.getDeviceId());
+                attributionSource.getAttributionTag(), attributionSource.getDeviceId());
     }
 
     /**
@@ -9481,23 +9597,26 @@
      */
     @UnsupportedAppUsage
     public int checkOpNoThrow(int op, int uid, String packageName) {
-        return checkOpNoThrow(op, uid, packageName, Context.DEVICE_ID_DEFAULT);
+        return checkOpNoThrow(op, uid, packageName, null, Context.DEVICE_ID_DEFAULT);
     }
 
-    private int checkOpNoThrow(int op, int uid, String packageName, int virtualDeviceId) {
+    private int checkOpNoThrow(int op, int uid, String packageName, @Nullable String attributionTag,
+            int virtualDeviceId) {
         try {
             int mode;
             if (isAppOpModeCachingEnabled(op)) {
                 mode = sAppOpModeCache.query(
-                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, null,
+                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
                                 "checkOpNoThrow"));
                 if (mode == MODE_FOREGROUND) {
                     // We only cache raw mode. If the mode is FOREGROUND, we need another binder
                     // call to fetch translated value based on the process state.
-                    mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId);
+                    mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag,
+                            virtualDeviceId);
                 }
             } else {
-                mode = mService.checkOperationForDevice(op, uid, packageName, virtualDeviceId);
+                mode = mService.checkOperationForDevice(op, uid, packageName, attributionTag,
+                        virtualDeviceId);
             }
             return mode;
         } catch (RemoteException e) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index e2479169..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 {
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..0668958 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,
@@ -864,7 +864,8 @@
 
     /**
      * Suppress or reenable the rate limit on foreground service notification deferral.
-     * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG.
+     * This is for use within CTS and is protected by android.permission.WRITE_DEVICE_CONFIG
+     * and WRITE_ALLOWLISTED_DEVICE_CONFIG.
      *
      * @param enable false to suppress rate-limit policy; true to reenable it.
      */
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index ec7b72e..c6f62a2 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -242,8 +242,8 @@
 
     boolean supportsLocalVoiceInteraction();
 
-    // Sets whether system educational dialogs should be limited
-    void setLimitSystemEducationDialogs(IBinder appToken, boolean limitSystemEducationDialogs);
+    // Requests the "Open in browser" education to be shown
+    void requestOpenInBrowserEducation(IBinder appToken);
 
     // Get device configuration
     ConfigurationInfo getDeviceConfigurationInfo();
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 62820ad..67f7bee 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -52,7 +53,9 @@
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.IDeviceLockedStateListener;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardLockedStateListener;
 import com.android.internal.util.Preconditions;
@@ -253,6 +256,26 @@
     private final ArrayMap<KeyguardLockedStateListener, Executor>
             mKeyguardLockedStateListeners = new ArrayMap<>();
 
+    private final IDeviceLockedStateListener mIDeviceLockedStateListener =
+            new IDeviceLockedStateListener.Stub() {
+                @Override
+                public void onDeviceLockedStateChanged(boolean isDeviceLocked) {
+                    if (!Flags.deviceUnlockListener()) {
+                        return;
+                    }
+                    synchronized (mDeviceLockedStateListeners) {
+                        mDeviceLockedStateListeners.forEach((listener, executor) -> {
+                            executor.execute(
+                                    () -> listener.onDeviceLockedStateChanged(isDeviceLocked));
+                        });
+                    }
+                }
+            };
+
+    @GuardedBy("mDeviceLockedStateListeners")
+    private final ArrayMap<DeviceLockedStateListener, Executor>
+            mDeviceLockedStateListeners = new ArrayMap<>();
+
     /**
      * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
      * if enrolled) for the current user of the device. The caller is expected to launch this
@@ -1370,4 +1393,77 @@
             }
         }
     }
+
+
+    /**
+     * Listener for device locked state changes.
+     */
+    @FunctionalInterface
+    @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+    public interface DeviceLockedStateListener {
+        /**
+         * Callback function that executes when the device locked state changes.
+         */
+        void onDeviceLockedStateChanged(boolean isDeviceLocked);
+    }
+
+
+    /**
+     * Registers a listener to execute when the device locked state changes.
+     *
+     * @param executor The {@link Executor} where the {@code listener} will be invoked
+     * @param listener The listener to add to receive device locked state changes.
+     *
+     * @see #isDeviceLocked()
+     * @see #removeDeviceLockedStateListener(DeviceLockedStateListener)
+     */
+    @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+    @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+    public void addDeviceLockedStateListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull DeviceLockedStateListener listener) {
+        if (!Flags.deviceUnlockListener()) {
+            return;
+        }
+
+        synchronized (mDeviceLockedStateListeners) {
+            mDeviceLockedStateListeners.put(listener, executor);
+            if (mDeviceLockedStateListeners.size() > 1) {
+                return;
+            }
+            try {
+                mTrustManager.registerDeviceLockedStateListener(mIDeviceLockedStateListener,
+                        mContext.getDeviceId());
+            } catch (RemoteException re) {
+                Log.d(TAG, "TrustManager service died", re);
+            }
+        }
+    }
+
+    /**
+     * Unregisters a listener that executes when the device locked state changes.
+     *
+     * @param listener The listener to remove.
+     *
+     * @see #isDeviceLocked()
+     * @see #addDeviceLockedStateListener(Executor, DeviceLockedStateListener)
+     */
+    @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+    @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER)
+    public void removeDeviceLockedStateListener(@NonNull DeviceLockedStateListener listener) {
+        if (!Flags.deviceUnlockListener()) {
+            return;
+        }
+
+        synchronized (mDeviceLockedStateListeners) {
+            mDeviceLockedStateListeners.remove(listener);
+            if (!mDeviceLockedStateListeners.isEmpty()) {
+                return;
+            }
+            try {
+                mTrustManager.unregisterDeviceLockedStateListener(mIDeviceLockedStateListener);
+            } catch (RemoteException re) {
+                Log.d(TAG, "TrustManager service died", re);
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3d9c55c..ff73382 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -811,6 +811,27 @@
     }
 
     private static boolean isStandardLayout(int layoutId) {
+        if (Flags.notificationsRedesignTemplates()) {
+            return switch (layoutId) {
+                case R.layout.notification_2025_template_collapsed_base,
+                     R.layout.notification_2025_template_heads_up_base,
+                     R.layout.notification_2025_template_header,
+                     R.layout.notification_template_material_big_base,
+                     R.layout.notification_template_material_big_picture,
+                     R.layout.notification_template_material_big_text,
+                     R.layout.notification_template_material_inbox,
+                     R.layout.notification_template_material_messaging,
+                     R.layout.notification_template_material_big_messaging,
+                     R.layout.notification_template_material_conversation,
+                     R.layout.notification_template_material_media,
+                     R.layout.notification_template_material_big_media,
+                     R.layout.notification_template_material_call,
+                     R.layout.notification_template_material_big_call,
+                     R.layout.notification_template_header -> true;
+                case R.layout.notification_template_material_progress -> Flags.apiRichOngoing();
+                default -> false;
+            };
+        }
         if (Flags.apiRichOngoing()) {
             if (layoutId == R.layout.notification_template_material_progress) {
                 return true;
@@ -6718,7 +6739,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,13 +7499,29 @@
             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() {
-            return R.layout.notification_template_material_heads_up_base;
+            if (Flags.notificationsRedesignTemplates()) {
+                return R.layout.notification_2025_template_heads_up_base;
+            } else {
+                return R.layout.notification_template_material_heads_up_base;
+            }
         }
 
         private int getCompactHeadsUpBaseLayoutResource() {
@@ -9499,7 +9536,6 @@
                 contentView.setViewVisibility(R.id.icon, View.GONE);
                 contentView.setViewVisibility(R.id.conversation_face_pile, View.GONE);
                 contentView.setViewVisibility(R.id.conversation_icon, View.VISIBLE);
-                contentView.setBoolean(R.id.conversation_icon, "setApplyCircularCrop", true);
                 contentView.setImageViewIcon(R.id.conversation_icon, conversationIcon);
             } else if (mIsGroupConversation) {
                 contentView.setViewVisibility(R.id.icon, View.GONE);
@@ -11527,11 +11563,9 @@
             contentView.setBundle(R.id.progress,
                     "setProgressModel", model.toBundle());
 
-            if (mTrackerIcon != null) {
-                contentView.setIcon(R.id.progress,
-                        "setProgressTrackerIcon",
-                        mTrackerIcon);
-            }
+            contentView.setIcon(R.id.progress,
+                    "setProgressTrackerIcon",
+                    mTrackerIcon);
 
             return contentView;
         }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c49b022..c310f95 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.service.notification.Flags.notificationClassification;
 
 import android.annotation.CallbackExecutor;
@@ -1597,11 +1599,15 @@
      * Returns whether notifications from the calling package are enabled.
      */
     public boolean areNotificationsEnabled() {
-        INotificationManager service = getService();
-        try {
-            return service.areNotificationsEnabled(mContext.getPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+        if (Flags.nmBinderPerfPermissionCheck()) {
+            return mContext.checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED;
+        } else {
+            INotificationManager service = getService();
+            try {
+                return service.areNotificationsEnabled(mContext.getPackageName());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
     }
 
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 1dc7742..e218418 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -314,6 +314,14 @@
     @GuardedBy("mLock")
     private long mMisses = 0;
 
+    // This counter tracks the number of times {@link #recompute} returned a null value.  Null
+    // results are cached, or not, depending on instantiation arguments.  Caching nulls when they
+    // should not be cached is a functional error. Failing to cache nulls that can be cached is a
+    // performance error.  A non-zero value here means the cache should be examined to be sure
+    // that nulls are correctly cached, or not.
+    @GuardedBy("mLock")
+    private long mNulls = 0;
+
     @GuardedBy("mLock")
     private long[] mSkips = new long[MAX_RESERVED_NONCE + 1];
 
@@ -374,6 +382,11 @@
     private final String mCacheName;
 
     /**
+     * True if nulls are valid returns from recompute().
+     */
+    private final boolean mCacheNullResults;
+
+    /**
      * The function that computes a Result, given a Query.  This function is called on a
      * cache miss.
      */
@@ -509,6 +522,19 @@
         }
 
         /**
+         * Return true if the entry is in the cache.
+         */
+        boolean containsKey(Query query) {
+            final int uid = callerUid();
+            var map = mCache.get(uid);
+            if (map != null) {
+                return map.containsKey(query);
+            } else {
+                return false;
+            }
+        }
+
+        /**
          * Remove an entry from the cache.
          */
         void remove(Query query) {
@@ -1101,7 +1127,7 @@
      * @hide
      */
     public static record Args(@NonNull String mModule, @Nullable String mApi,
-            int mMaxEntries, boolean mIsolateUids, boolean mTestMode) {
+            int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) {
 
         // Validation: the module must be one of the known module strings and the maxEntries must
         // be positive.
@@ -1119,24 +1145,29 @@
                     null,       // api
                     32,         // maxEntries
                     true,       // isolateUids
-                    false       // testMode
+                    false,      // testMode
+                    true        // allowNulls
                  );
         }
 
         public Args api(@NonNull String api) {
-            return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode);
+            return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode, mCacheNulls);
         }
 
         public Args maxEntries(int val) {
-            return new Args(mModule, mApi, val, mIsolateUids, mTestMode);
+            return new Args(mModule, mApi, val, mIsolateUids, mTestMode, mCacheNulls);
         }
 
         public Args isolateUids(boolean val) {
-            return new Args(mModule, mApi, mMaxEntries, val, mTestMode);
+            return new Args(mModule, mApi, mMaxEntries, val, mTestMode, mCacheNulls);
         }
 
         public Args testMode(boolean val) {
-            return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val);
+            return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val, mCacheNulls);
+        }
+
+        public Args cacheNulls(boolean val) {
+            return new Args(mModule, mApi, mMaxEntries, mIsolateUids, mTestMode, val);
         }
     }
 
@@ -1153,6 +1184,7 @@
             @Nullable QueryHandler<Query, Result> computer) {
         mPropertyName = createPropertyName(args.mModule, args.mApi);
         mCacheName = cacheName;
+        mCacheNullResults = args.mCacheNulls && Flags.picCacheNulls();
         mNonce = getNonceHandler(mPropertyName);
         mMaxEntries = args.mMaxEntries;
         mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode);
@@ -1491,12 +1523,24 @@
                 }
                 return recompute(query);
             }
+
+            final boolean cacheHit;
             final Result cachedResult;
             synchronized (mLock) {
                 if (currentNonce == mLastSeenNonce) {
                     cachedResult = mCache.get(query);
-
-                    if (cachedResult != null) mHits++;
+                    if (cachedResult == null) {
+                        if (mCacheNullResults) {
+                            cacheHit = mCache.containsKey(query);
+                        } else {
+                            cacheHit = false;
+                        }
+                    } else {
+                        cacheHit = true;
+                    }
+                    if (cacheHit) {
+                        mHits++;
+                    }
                 } else {
                     if (DEBUG) {
                         Log.d(TAG, formatSimple(
@@ -1506,16 +1550,18 @@
                     }
                     clear();
                     mLastSeenNonce = currentNonce;
+                    cacheHit = false;
                     cachedResult = null;
                 }
             }
+
             // Cache hit --- but we're not quite done yet.  A value in the cache might need to
             // be augmented in a "refresh" operation.  The refresh operation can combine the
             // old and the new nonce values.  In order to make sure the new parts of the value
             // are consistent with the old, possibly-reused parts, we check the property value
             // again after the refresh and do the whole fetch again if the property invalidated
             // us while we were refreshing.
-            if (cachedResult != null) {
+            if (cacheHit) {
                 final Result refreshedResult = refresh(cachedResult, query);
                 if (refreshedResult != cachedResult) {
                     if (DEBUG) {
@@ -1550,6 +1596,7 @@
                 }
                 return maybeCheckConsistency(query, cachedResult);
             }
+
             // Cache miss: make the value from scratch.
             if (DEBUG) {
                 Log.d(TAG, "cache miss for " + cacheName() + " " + queryToString(query));
@@ -1558,8 +1605,13 @@
             synchronized (mLock) {
                 // If someone else invalidated the cache while we did the recomputation, don't
                 // update the cache with a potentially stale result.
-                if (mLastSeenNonce == currentNonce && result != null) {
-                    mCache.put(query, result);
+                if (mLastSeenNonce == currentNonce) {
+                    if (result != null || mCacheNullResults) {
+                        mCache.put(query, result);
+                    }
+                    if (result == null) {
+                        mNulls++;
+                    }
                 }
                 mMisses++;
             }
@@ -1947,10 +1999,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 +2022,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, Nulls: %d",
+                mHits, mMisses, getSkipsLocked(), mClears, mNulls));
 
             // Print all the skip reasons.
             pw.format("    Skip-%s: %d", sNonceName[0], mSkips[0]);
@@ -1986,7 +2040,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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index ee0c38c..6a23349 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;
@@ -216,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;
@@ -239,6 +241,10 @@
 import android.security.advancedprotection.IAdvancedProtectionService;
 import android.security.attestationverification.AttestationVerificationManager;
 import android.security.attestationverification.IAttestationVerificationManagerService;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.IAuthenticationPolicyService;
+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;
@@ -1021,6 +1027,25 @@
                     }
                 });
 
+        registerService(Context.AUTHENTICATION_POLICY_SERVICE,
+                AuthenticationPolicyManager.class,
+                new CachedServiceFetcher<AuthenticationPolicyManager>() {
+                    @Override
+                    public AuthenticationPolicyManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        if (!android.security.Flags.secureLockdown()) {
+                            throw new ServiceNotFoundException(
+                                    Context.AUTHENTICATION_POLICY_SERVICE);
+                        }
+
+                        final IBinder binder = ServiceManager.getServiceOrThrow(
+                                Context.AUTHENTICATION_POLICY_SERVICE);
+                        final IAuthenticationPolicyService service =
+                                IAuthenticationPolicyService.Stub.asInterface(binder);
+                        return new AuthenticationPolicyManager(ctx.getOuterContext(), service);
+                    }
+                });
+
         registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class,
                 new CachedServiceFetcher<TvInteractiveAppManager>() {
             @Override
@@ -1793,6 +1818,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
@@ -1821,7 +1858,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/TaskInfo.java b/core/java/android/app/TaskInfo.java
index aac963a..01cc9d8 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -340,10 +340,10 @@
     public int requestedVisibleTypes;
 
     /**
-     * Whether the top activity has requested to limit educational dialogs shown by the system.
+     * The timestamp of the top activity's last request to show the "Open in Browser" education.
      * @hide
      */
-    public boolean isTopActivityLimitSystemEducationDialogs;
+    public long topActivityRequestOpenInBrowserEducationTimestamp;
 
     /**
      * Encapsulate specific App Compat information.
@@ -493,8 +493,8 @@
                 && Objects.equals(capturedLink, that.capturedLink)
                 && capturedLinkTimestamp == that.capturedLinkTimestamp
                 && requestedVisibleTypes == that.requestedVisibleTypes
-                && isTopActivityLimitSystemEducationDialogs
-                    == that.isTopActivityLimitSystemEducationDialogs
+                && topActivityRequestOpenInBrowserEducationTimestamp
+                    == that.topActivityRequestOpenInBrowserEducationTimestamp
                 && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo)
                 && Objects.equals(topActivityMainWindowFrame, that.topActivityMainWindowFrame);
     }
@@ -571,7 +571,7 @@
         capturedLink = source.readTypedObject(Uri.CREATOR);
         capturedLinkTimestamp = source.readLong();
         requestedVisibleTypes = source.readInt();
-        isTopActivityLimitSystemEducationDialogs = source.readBoolean();
+        topActivityRequestOpenInBrowserEducationTimestamp = source.readLong();
         appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
         topActivityMainWindowFrame = source.readTypedObject(Rect.CREATOR);
     }
@@ -627,7 +627,7 @@
         dest.writeTypedObject(capturedLink, flags);
         dest.writeLong(capturedLinkTimestamp);
         dest.writeInt(requestedVisibleTypes);
-        dest.writeBoolean(isTopActivityLimitSystemEducationDialogs);
+        dest.writeLong(topActivityRequestOpenInBrowserEducationTimestamp);
         dest.writeTypedObject(appCompatTaskInfo, flags);
         dest.writeTypedObject(topActivityMainWindowFrame, flags);
     }
@@ -672,8 +672,8 @@
                 + " capturedLink=" + capturedLink
                 + " capturedLinkTimestamp=" + capturedLinkTimestamp
                 + " requestedVisibleTypes=" + requestedVisibleTypes
-                + " isTopActivityLimitSystemEducationDialogs="
-                + isTopActivityLimitSystemEducationDialogs
+                + " topActivityRequestOpenInBrowserEducationTimestamp="
+                + topActivityRequestOpenInBrowserEducationTimestamp
                 + " appCompatTaskInfo=" + appCompatTaskInfo
                 + " topActivityMainWindowFrame=" + topActivityMainWindowFrame
                 + "}";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4e68b5a..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;
@@ -17196,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 {
@@ -17218,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 fa984af..d048b53 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -570,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/keyguard.aconfig b/core/java/android/app/keyguard.aconfig
new file mode 100644
index 0000000..9cd1c15
--- /dev/null
+++ b/core/java/android/app/keyguard.aconfig
@@ -0,0 +1,10 @@
+package: "android.app"
+container: "system"
+
+flag {
+     namespace: "wallet_integration"
+     name: "device_unlock_listener"
+     is_exported: true
+     description: "Enable listener API for device unlock."
+     bug: "296195355"
+}
\ No newline at end of file
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index a487da2..8b6840c 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"
@@ -270,6 +277,13 @@
 }
 
 flag {
+  name: "nm_binder_perf_permission_check"
+  namespace: "systemui"
+  description: "Use PermissionManager for areNotificationsEnabled() instead of NMS"
+  bug: "362981561"
+}
+
+flag {
   name: "no_sbnholder"
   namespace: "systemui"
   description: "removes sbnholder from NLS"
diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig
index 61b53f9..359c84e 100644
--- a/core/java/android/app/performance.aconfig
+++ b/core/java/android/app/performance.aconfig
@@ -35,3 +35,10 @@
      bug: "373752556"
 }
 
+flag {
+     namespace: "system_performance"
+     name: "pic_cache_nulls"
+     is_fixed_read_only: true
+     description: "Cache null returns from binder calls"
+     bug: "372923336"
+}
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/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 730bb73..ffa5488 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.trust.ITrustListener;
 import android.hardware.biometrics.BiometricSourceType;
+import com.android.internal.policy.IDeviceLockedStateListener;
 
 /**
  * System private API to comunicate with trust service.
@@ -43,4 +44,8 @@
     boolean isActiveUnlockRunning(int userId);
     @EnforcePermission("ACCESS_FINE_LOCATION")
     boolean isInSignificantPlace();
+    @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE")
+    void registerDeviceLockedStateListener(in IDeviceLockedStateListener listener, int deviceId);
+    @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE")
+    void unregisterDeviceLockedStateListener(in IDeviceLockedStateListener listener);
 }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 1ef83cd..8c8970e 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -31,6 +31,8 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 
+import com.android.internal.policy.IDeviceLockedStateListener;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -259,6 +261,35 @@
     }
 
     /**
+     * Registers a listener for device lock state events.
+     *
+     * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE}
+     * permission.
+     */
+    public void registerDeviceLockedStateListener(final IDeviceLockedStateListener listener,
+            int deviceId) {
+        try {
+            mService.registerDeviceLockedStateListener(listener, deviceId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregisters a listener for device lock state events.
+     *
+     * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE}
+     * permission.
+     */
+    public void unregisterDeviceLockedStateListener(final IDeviceLockedStateListener listener) {
+        try {
+            mService.unregisterDeviceLockedStateListener(listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @return whether {@param userId} has enabled and configured trust agents. Ignores short-term
      * unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}.
      */
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/Context.java b/core/java/android/content/Context.java
index 6086f24..19cd2e6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -18,6 +18,7 @@
 
 import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
 import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
 
 import android.annotation.AttrRes;
 import android.annotation.CallbackExecutor;
@@ -4256,6 +4257,7 @@
             FINGERPRINT_SERVICE,
             //@hide: FACE_SERVICE,
             BIOMETRIC_SERVICE,
+            AUTHENTICATION_POLICY_SERVICE,
             MEDIA_ROUTER_SERVICE,
             TELEPHONY_SERVICE,
             TELEPHONY_SUBSCRIPTION_SERVICE,
@@ -4437,6 +4439,9 @@
      * web domain approval state.
      * <dt> {@link #DISPLAY_HASH_SERVICE} ("display_hash")
      * <dd> A {@link android.view.displayhash.DisplayHashManager} for management of display hashes.
+     * <dt> {@link #AUTHENTICATION_POLICY_SERVICE} ("authentication_policy")
+     * <dd> A {@link android.security.authenticationpolicy.AuthenticationPolicyManager}
+     * for managing authentication related policies on the device.
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -4521,8 +4526,9 @@
      * @see android.content.pm.verify.domain.DomainVerificationManager
      * @see #DISPLAY_HASH_SERVICE
      * @see android.view.displayhash.DisplayHashManager
+     * @see #AUTHENTICATION_POLICY_SERVICE
+     * @see android.security.authenticationpolicy.AuthenticationPolicyManager
      */
-    // TODO(b/347269120): Re-add @Nullable
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
     /**
@@ -4543,7 +4549,8 @@
      * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
      * {@link android.app.usage.NetworkStatsManager},
      * {@link android.content.pm.verify.domain.DomainVerificationManager},
-     * {@link android.view.displayhash.DisplayHashManager}.
+     * {@link android.view.displayhash.DisplayHashManager}
+     * {@link android.security.authenticationpolicy.AuthenticationPolicyManager}.
      * </p>
      *
      * <p>
@@ -4568,7 +4575,6 @@
      */
     @SuppressWarnings("unchecked")
     @RavenwoodKeep
-    // TODO(b/347269120): Re-add @Nullable
     public final <T> T getSystemService(@NonNull Class<T> serviceClass) {
         // Because subclasses may override getSystemService(String) we cannot
         // perform a lookup by class alone.  We must first map the class to its
@@ -5183,6 +5189,18 @@
     public static final String AUTH_SERVICE = "auth";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an {@link
+     * android.security.authenticationpolicy.AuthenticationPolicyManager}.
+     * @see #getSystemService
+     * @see android.security.authenticationpolicy.AuthenticationPolicyManager
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final String AUTHENTICATION_POLICY_SERVICE = "authentication_policy";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 23d17cb..413eb98 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -960,7 +960,6 @@
     }
 
     @Override
-    // TODO(b/347269120): Re-add @Nullable
     public Object getSystemService(String name) {
         return mBase.getSystemService(name);
     }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index ce52825..b10f5e4 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1320,23 +1320,23 @@
             264301586L; // buganizer id
 
     /**
-     * Excludes the packages the override is applied to from the camera compatibility treatment
-     * in free-form windowing mode for fixed-orientation apps.
+     * Includes the packages the override is applied to in the camera compatibility treatment in
+     * free-form windowing mode for fixed-orientation apps.
      *
      * <p>In free-form windowing mode, the compatibility treatment emulates running on a portrait
      * device by letterboxing the app window and changing the camera characteristics to what apps
      * commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front
      * cameras, respectively, and setting display rotation to 0.
      *
-     * <p>Use this flag to disable the compatibility treatment for apps that do not respond well to
-     * the treatment.
+     * <p>Use this flag to enable the compatibility treatment for apps in which camera doesn't work
+     * well in freeform windowing.
      *
      * @hide
      */
     @ChangeId
     @Overridable
     @Disabled
-    public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT =
+    public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT =
             314961188L;
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3152ff4..5b305b4 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;
+        }
     }
 
     /**
@@ -3126,6 +3200,16 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device is capable of ranging with
+     * other devices using channel sounding via Bluetooth Low Energy radio.
+     */
+    @FlaggedApi(com.android.ranging.flags.Flags.FLAG_RANGING_CS_ENABLED)
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING =
+             "android.hardware.bluetooth_le.channel_sounding";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a camera facing away
      * from the screen.
      */
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/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
new file mode 100644
index 0000000..06fcabc
--- /dev/null
+++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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;
+
+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/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index e9e8578..05c8f31 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -537,6 +537,9 @@
                                     hasBindDeviceAdminPermission);
                             break;
                         case TAG_USES_SDK_LIBRARY:
+                            if (!android.content.pm.Flags.sdkDependencyInstaller()) {
+                                break;
+                            }
                             String usesSdkLibName = parser.getAttributeValue(
                                     ANDROID_RES_NAMESPACE, "name");
                             long usesSdkLibVersionMajor = parser.getAttributeIntValue(
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..581040d
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubDiscoveryInfo.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 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.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}.
+ *
+ * <p>Application may use the values {@link #getHubEndpointInfo} to retrieve the {@link
+ * HubEndpointInfo} that describes the endpoint that matches the query.
+ *
+ * <p>Application may use the values {@link #getHubServiceInfo()} to retrieve the {@link
+ * HubServiceInfo} that describes the service that matches the query.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public class HubDiscoveryInfo {
+    @NonNull private final HubEndpointInfo mEndpointInfo;
+    @Nullable private final HubServiceInfo mServiceInfo;
+
+    /** @hide */
+    public HubDiscoveryInfo(@NonNull HubEndpointInfo endpointInfo) {
+        mEndpointInfo = endpointInfo;
+        mServiceInfo = null;
+    }
+
+    /** @hide */
+    public HubDiscoveryInfo(
+            @NonNull HubEndpointInfo endpointInfo, @NonNull HubServiceInfo serviceInfo) {
+        mEndpointInfo = endpointInfo;
+        mServiceInfo = serviceInfo;
+    }
+
+    /** Get the {@link HubEndpointInfo} for the endpoint found. */
+    @NonNull
+    public HubEndpointInfo getHubEndpointInfo() {
+        return mEndpointInfo;
+    }
+
+    /**
+     * Get the {@link HubServiceInfo} for the endpoint found. The value will be null if there is no
+     * service info specified in the query.
+     */
+    @Nullable
+    public HubServiceInfo getHubServiceInfo() {
+        return mServiceInfo;
+    }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
new file mode 100644
index 0000000..078b4d4
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -0,0 +1,559 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+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,
+                        @Nullable HubServiceInfo serviceInfo)
+                        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,
+                                                serviceInfo,
+                                                mLifecycleCallback.onSessionOpenRequest(
+                                                        initiator, serviceInfo)));
+                    }
+                }
+
+                private void processSessionOpenRequestResult(
+                        int sessionId,
+                        HubEndpointInfo initiator,
+                        @Nullable HubServiceInfo serviceInfo,
+                        HubEndpointSessionResult result) {
+                    if (result == null) {
+                        throw new IllegalArgumentException(
+                                "HubEndpointSessionResult shouldn't be null.");
+                    }
+
+                    if (result.isAccepted()) {
+                        acceptSession(sessionId, initiator, serviceInfo);
+                    } else {
+                        Log.i(
+                                TAG,
+                                "Session "
+                                        + sessionId
+                                        + " from "
+                                        + initiator
+                                        + " was rejected, reason="
+                                        + result.getReason());
+                        rejectSession(sessionId);
+                    }
+                }
+
+                private void acceptSession(
+                        int sessionId,
+                        HubEndpointInfo initiator,
+                        @Nullable HubServiceInfo serviceInfo) {
+                    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,
+                                        serviceInfo);
+                        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, @Nullable HubServiceInfo serviceInfo) {
+        // 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, serviceInfo);
+
+            // Save the newly created session
+            synchronized (mLock) {
+                newSession =
+                        new HubEndpointSession(
+                                sessionId,
+                                HubEndpoint.this,
+                                destinationInfo,
+                                mAssignedHubEndpointInfo,
+                                serviceInfo);
+                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();
+        }
+    }
+
+    public int getVersion() {
+        return mPendingHubEndpointInfo.getVersion();
+    }
+
+    @Nullable
+    public String getTag() {
+        return mPendingHubEndpointInfo.getTag();
+    }
+
+    @NonNull
+    public Collection<HubServiceInfo> getServiceInfoCollection() {
+        return mPendingHubEndpointInfo.getServiceInfoCollection();
+    }
+
+    @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;
+
+        private int mVersion;
+        @Nullable private String mTag;
+
+        private List<HubServiceInfo> mServiceInfos = Collections.emptyList();
+
+        /** Create a builder for {@link HubEndpoint} */
+        public Builder(@NonNull Context context) {
+            mPackageName = context.getPackageName();
+            mVersion = (int) context.getApplicationInfo().longVersionCode;
+            mLifecycleCallbackExecutor = context.getMainExecutor();
+            mMessageCallbackExecutor = context.getMainExecutor();
+        }
+
+        /**
+         * Set the version for the endpoint. Default is 0.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setVersion(int version) {
+            mVersion = version;
+            return this;
+        }
+
+        /**
+         * 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;
+        }
+
+        /**
+         * Add a service to the available services from this endpoint. The {@link HubServiceInfo}
+         * object can be built with {@link HubServiceInfo.Builder}.
+         */
+        @NonNull
+        public Builder setServiceInfoCollection(
+                @NonNull Collection<HubServiceInfo> hubServiceInfos) {
+            // Make a copy first
+            mServiceInfos = new ArrayList<>(hubServiceInfos);
+            return this;
+        }
+
+        /** Build the {@link HubEndpoint} object. */
+        @NonNull
+        public HubEndpoint build() {
+            return new HubEndpoint(
+                    new HubEndpointInfo(mPackageName, mVersion, mTag, mServiceInfos),
+                    mLifecycleCallback,
+                    mLifecycleCallbackExecutor,
+                    mMessageCallback,
+                    mMessageCallbackExecutor);
+        }
+    }
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.aidl b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
new file mode 100644
index 0000000..025b2b1
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+/** @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..b1d5523
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java
@@ -0,0 +1,330 @@
+/*
+ * 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.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+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;
+        }
+    }
+
+    /** This endpoint is from the Android framework */
+    public static final int TYPE_FRAMEWORK = 1;
+
+    /** This endpoint is from an Android app */
+    public static final int TYPE_APP = 2;
+
+    /** This endpoint is from an Android native program. */
+    public static final int TYPE_NATIVE = 3;
+
+    /** This endpoint is from a nanoapp. */
+    public static final int TYPE_NANOAPP = 4;
+
+    /** This endpoint is a generic endpoint served by a hub (not from a nanoapp). */
+    public static final int TYPE_HUB_ENDPOINT = 5;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        TYPE_FRAMEWORK,
+        TYPE_APP,
+        TYPE_NATIVE,
+        TYPE_NANOAPP,
+        TYPE_HUB_ENDPOINT,
+    })
+    public @interface EndpointType {}
+
+    private final HubEndpointIdentifier mId;
+    @EndpointType private final int mType;
+    private final String mName;
+    private final int mVersion;
+    @Nullable private final String mTag;
+
+    @NonNull private final List<String> mRequiredPermissions;
+    @NonNull private final List<HubServiceInfo> mHubServiceInfos;
+
+    /** @hide */
+    public HubEndpointInfo(android.hardware.contexthub.EndpointInfo endpointInfo) {
+        mId = new HubEndpointIdentifier(endpointInfo.id.hubId, endpointInfo.id.id);
+        mType = endpointInfo.type;
+        mName = endpointInfo.name;
+        mVersion = endpointInfo.version;
+        mTag = endpointInfo.tag;
+        mRequiredPermissions = Arrays.asList(endpointInfo.requiredPermissions);
+        mHubServiceInfos = new ArrayList<>(endpointInfo.services.length);
+        for (int i = 0; i < endpointInfo.services.length; i++) {
+            mHubServiceInfos.set(i, new HubServiceInfo(endpointInfo.services[i]));
+        }
+    }
+
+    /** @hide */
+    public HubEndpointInfo(
+            String name,
+            int version,
+            @Nullable String tag,
+            @NonNull List<HubServiceInfo> hubServiceInfos) {
+        mId = HubEndpointIdentifier.invalid();
+        mType = TYPE_APP;
+        mName = name;
+        mVersion = version;
+        mTag = tag;
+        mRequiredPermissions = Collections.emptyList();
+        mHubServiceInfos = hubServiceInfos;
+    }
+
+    private HubEndpointInfo(Parcel in) {
+        long hubId = in.readLong();
+        long endpointId = in.readLong();
+        mId = new HubEndpointIdentifier(hubId, endpointId);
+        mType = in.readInt();
+        mName = in.readString();
+        mVersion = in.readInt();
+        mTag = in.readString();
+        mRequiredPermissions = new ArrayList<>();
+        in.readStringList(mRequiredPermissions);
+        mHubServiceInfos = new ArrayList<>();
+        in.readTypedList(mHubServiceInfos, HubServiceInfo.CREATOR);
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public int describeContents() {
+        int flags = 0;
+        for (HubServiceInfo serviceInfo : mHubServiceInfos) {
+            flags |= serviceInfo.describeContents();
+        }
+        return flags;
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeLong(mId.getHub());
+        dest.writeLong(mId.getEndpoint());
+        dest.writeInt(mType);
+        dest.writeString(mName);
+        dest.writeInt(mVersion);
+        dest.writeString(mTag);
+        dest.writeStringList(mRequiredPermissions);
+        dest.writeTypedList(mHubServiceInfos, flags);
+    }
+
+    /** Get a unique identifier for this endpoint. */
+    @NonNull
+    public HubEndpointIdentifier getIdentifier() {
+        return mId;
+    }
+
+    /**
+     * Get the type of this endpoint. Application may use this field to get more information about
+     * who registered this endpoint for diagnostic purposes.
+     *
+     * <p>Type can be one of {@link HubEndpointInfo#TYPE_APP}, {@link
+     * HubEndpointInfo#TYPE_FRAMEWORK}, {@link HubEndpointInfo#TYPE_NANOAPP}, {@link
+     * HubEndpointInfo#TYPE_NATIVE} or {@link HubEndpointInfo#TYPE_HUB_ENDPOINT}.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /** Get the human-readable name of this endpoint (for debugging purposes). */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Get the version of this endpoint.
+     *
+     * <p>Monotonically increasing version number. The two sides of an endpoint session can use this
+     * version number to identify the other side and determine compatibility with each other. The
+     * interpretation of the version number is specific to the implementation of an endpoint.
+     *
+     * <p>The version number should not be used to compare endpoints implementation freshness for
+     * different endpoint types.
+     *
+     * <p>Depending on type of the endpoint, the following values (and formats) are used:
+     *
+     * <ol>
+     *   <li>{@link #TYPE_FRAMEWORK}: android.os.Build.VERSION.SDK_INT_FULL
+     *   <li>{@link #TYPE_APP}: versionCode
+     *   <li>{@link #TYPE_NATIVE}: unspecified format (supplied by endpoint code)
+     *   <li>{@link #TYPE_NANOAPP}: nanoapp version, typically following 0xMMmmpppp scheme where MM
+     *       = major version, mm = minor version, pppp = patch version
+     *   <li>{@link #TYPE_HUB_ENDPOINT}: unspecified format (supplied by endpoint code), following
+     *       nanoapp versioning scheme is recommended
+     * </ol>
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Get the list of required permissions in order to talk to this endpoint.
+     *
+     * <p>This list is enforced by the Context Hub Service. The app would need to have the required
+     * permissions list to open a session with this particular endpoint. Otherwise this will be
+     * rejected by as permission failures.
+     *
+     * <p>This is mostly for allowing app to check what permission it needs first internally. App
+     * will need to request permissions grant at runtime if not already granted. See {@link
+     * android.content.Context#checkPermission} for more details.
+     *
+     * <p>See {@link android.Manifest.permission} for a list of standard Android permissions as
+     * possible values.
+     */
+    @SuppressLint("RequiresPermission")
+    @NonNull
+    public Collection<String> getRequiredPermissions() {
+        return Collections.unmodifiableList(mRequiredPermissions);
+    }
+
+    /**
+     * Get the list of services provided by this endpoint.
+     *
+     * <p>See {@link HubServiceInfo} for more information.
+     */
+    @NonNull
+    public Collection<HubServiceInfo> getServiceInfoCollection() {
+        return Collections.unmodifiableList(mHubServiceInfos);
+    }
+
+    @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..cf952cb
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -0,0 +1,170 @@
+/*
+ * 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.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;
+    @Nullable private final HubServiceInfo mServiceInfo;
+
+    private final AtomicBoolean mIsClosed = new AtomicBoolean(true);
+
+    /** @hide */
+    HubEndpointSession(
+            int id,
+            @NonNull HubEndpoint hubEndpoint,
+            @NonNull HubEndpointInfo destination,
+            @NonNull HubEndpointInfo initiator,
+            @Nullable HubServiceInfo serviceInfo) {
+        mId = id;
+        mHubEndpoint = hubEndpoint;
+        mDestination = destination;
+        mInitiator = initiator;
+        mServiceInfo = serviceInfo;
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    /**
+     * Get the {@link HubServiceInfo} associated with this session. Null value indicates that there
+     * is no service associated to this session.
+     *
+     * <p>For hub initiated sessions, the object was previously used in as an argument for open
+     * request in {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}.
+     *
+     * <p>For app initiated sessions, the object was previously used in an open request in {@link
+     * android.hardware.location.ContextHubManager#openSession}
+     */
+    @Nullable
+    public HubServiceInfo getServiceInfo() {
+        return mServiceInfo;
+    }
+
+    @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/core/java/android/hardware/contexthub/HubMessage.aidl b/core/java/android/hardware/contexthub/HubMessage.aidl
new file mode 100644
index 0000000..86afce2
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubMessage.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * @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/HubServiceInfo.aidl b/core/java/android/hardware/contexthub/HubServiceInfo.aidl
new file mode 100644
index 0000000..98b1bba
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+parcelable HubServiceInfo;
diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java
new file mode 100644
index 0000000..c7fe77c
--- /dev/null
+++ b/core/java/android/hardware/contexthub/HubServiceInfo.java
@@ -0,0 +1,263 @@
+/*
+ * 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.IntDef;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.chre.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelableHolder;
+
+import androidx.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * A class describing services provided by endpoints.
+ *
+ * <p>An endpoint can provide zero or more service. See {@link
+ * HubEndpoint.Builder#setServiceInfoCollection(Collection)} and {@link
+ * HubEndpointInfo#getServiceInfoCollection()}.
+ *
+ * <p>An endpoint session can be service-less or associated to one service.See {@link
+ * HubEndpointSession#getServiceInfo()}.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(Flags.FLAG_OFFLOAD_API)
+public final class HubServiceInfo implements Parcelable {
+    /** Customized format for messaging. Fully customized and opaque messaging format. */
+    public static final int FORMAT_CUSTOM = 0;
+
+    /**
+     * Binder-based messaging. The host endpoint is defining this service in Stable AIDL. Messages
+     * between endpoints that uses this service will be using the binder marhsalling format.
+     */
+    public static final int FORMAT_AIDL = 1;
+
+    /**
+     * Pigweed RPC messaging with Protobuf. This endpoint is a Pigweed RPC. Messages between
+     * endpoints will use Pigweed RPC marshalling format (protobuf).
+     */
+    public static final int FORMAT_PW_RPC_PROTOBUF = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        FORMAT_CUSTOM,
+        FORMAT_AIDL,
+        FORMAT_PW_RPC_PROTOBUF,
+    })
+    public @interface ServiceFormat {}
+
+    @NonNull private final String mServiceDescriptor;
+
+    @ServiceFormat private final int mFormat;
+    private final int mMajorVersion;
+    private final int mMinorVersion;
+
+    @NonNull private final ParcelableHolder mExtendedInfo;
+
+    /** @hide */
+    public HubServiceInfo(android.hardware.contexthub.Service service) {
+        mServiceDescriptor = service.serviceDescriptor;
+        mFormat = service.format;
+        mMajorVersion = service.majorVersion;
+        mMinorVersion = service.minorVersion;
+        mExtendedInfo = service.extendedInfo;
+    }
+
+    private HubServiceInfo(Parcel in) {
+        mServiceDescriptor = Objects.requireNonNull(in.readString());
+        mFormat = in.readInt();
+        mMajorVersion = in.readInt();
+        mMinorVersion = in.readInt();
+        mExtendedInfo = ParcelableHolder.CREATOR.createFromParcel(in);
+    }
+
+    public HubServiceInfo(
+            @NonNull String serviceDescriptor,
+            @ServiceFormat int format,
+            int majorVersion,
+            int minorVersion,
+            @NonNull ParcelableHolder extendedInfo) {
+        mServiceDescriptor = serviceDescriptor;
+        mFormat = format;
+        mMajorVersion = majorVersion;
+        mMinorVersion = minorVersion;
+        mExtendedInfo = extendedInfo;
+    }
+
+    /** Get the unique identifier of this service. See {@link Builder} for more information. */
+    @NonNull
+    public String getServiceDescriptor() {
+        return mServiceDescriptor;
+    }
+
+    /**
+     * Get the type of the service.
+     *
+     * <p>The value can be one of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
+     * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
+     */
+    public int getFormat() {
+        return mFormat;
+    }
+
+    /** Get the major version of this service. */
+    public int getMajorVersion() {
+        return mMajorVersion;
+    }
+
+    /** Get the minor version of this service. */
+    public int getMinorVersion() {
+        return mMinorVersion;
+    }
+
+    /** Get the {@link ParcelableHolder} for the extended information about the service. */
+    @NonNull
+    public ParcelableHolder getExtendedInfo() {
+        return mExtendedInfo;
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public int describeContents() {
+        // Passthrough describeContents flags for mExtendedInfo because we don't have FD otherwise.
+        return mExtendedInfo.describeContents();
+    }
+
+    /** Parcel implementation details */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mServiceDescriptor);
+        dest.writeInt(mFormat);
+        dest.writeInt(mMajorVersion);
+        dest.writeInt(mMinorVersion);
+        mExtendedInfo.writeToParcel(dest, flags);
+    }
+
+    /** Builder for a {@link HubServiceInfo} object. */
+    public static final class Builder {
+        @NonNull private final String mServiceDescriptor;
+
+        @ServiceFormat private final int mFormat;
+        private final int mMajorVersion;
+        private final int mMinorVersion;
+
+        private final ParcelableHolder mExtendedInfo =
+                new ParcelableHolder(Parcelable.PARCELABLE_STABILITY_VINTF);
+
+        /**
+         * Create a builder for {@link HubServiceInfo} with a service descriptor.
+         *
+         * <p>Service descriptor should uniquely identify the interface (scoped to type). Convention
+         * of the descriptor depend on interface type.
+         *
+         * <p>Examples:
+         *
+         * <ol>
+         *   <li>AOSP-defined AIDL: android.hardware.something.IFoo/default
+         *   <li>Vendor-defined AIDL: com.example.something.IBar/default
+         *   <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService
+         * </ol>
+         *
+         * @param serviceDescriptor The service descriptor.
+         * @param format One of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link
+         *     HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}.
+         * @param majorVersion Breaking changes should be a major version bump.
+         * @param minorVersion Monotonically increasing minor version.
+         * @throws IllegalArgumentException if one or more fields are not valid.
+         */
+        public Builder(
+                @NonNull String serviceDescriptor,
+                @ServiceFormat int format,
+                int majorVersion,
+                int minorVersion) {
+            if (format != FORMAT_CUSTOM
+                    && format != FORMAT_AIDL
+                    && format != FORMAT_PW_RPC_PROTOBUF) {
+                throw new IllegalArgumentException("Invalid format type.");
+            }
+            mFormat = format;
+
+            if (majorVersion < 0) {
+                throw new IllegalArgumentException(
+                        "Major version cannot be set to negative number.");
+            }
+            mMajorVersion = majorVersion;
+
+            if (minorVersion < 0) {
+                throw new IllegalArgumentException(
+                        "Minor version cannot be set to negative number.");
+            }
+            mMinorVersion = minorVersion;
+
+            if (serviceDescriptor.isBlank()) {
+                throw new IllegalArgumentException("Invalid service descriptor.");
+            }
+            mServiceDescriptor = serviceDescriptor;
+        }
+
+        /**
+         * Set the extended information of this service.
+         *
+         * @param extendedInfo Parcelable with extended information about this service. The
+         *     parcelable needs to have at least VINTF stability. Null can be used to clear a
+         *     previously set value.
+         * @throws android.os.BadParcelableException if the parcelable cannot be used.
+         */
+        @NonNull
+        public Builder setExtendedInfo(@Nullable Parcelable extendedInfo) {
+            mExtendedInfo.setParcelable(extendedInfo);
+            return this;
+        }
+
+        /**
+         * Build the {@link HubServiceInfo} object.
+         *
+         * @throws IllegalStateException if the Builder is missing required info.
+         */
+        @NonNull
+        public HubServiceInfo build() {
+            if (mMajorVersion < 0 || mMinorVersion < 0) {
+                throw new IllegalStateException("Major and minor version must be set.");
+            }
+            return new HubServiceInfo(
+                    mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion, mExtendedInfo);
+        }
+    }
+
+    /** Parcel implementation details */
+    @NonNull
+    public static final Parcelable.Creator<HubServiceInfo> CREATOR =
+            new Parcelable.Creator<>() {
+                public HubServiceInfo createFromParcel(Parcel in) {
+                    return new HubServiceInfo(in);
+                }
+
+                public HubServiceInfo[] newArray(int size) {
+                    return new HubServiceInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
new file mode 100644
index 0000000..1c98b4b
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl
@@ -0,0 +1,90 @@
+/*
+ * 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.contexthub.HubServiceInfo;
+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, in @nullable HubServiceInfo serviceInfo);
+
+    /**
+     * 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..1ae5fb9
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.contexthub.HubServiceInfo;
+
+/**
+  * @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
+     * @param serviceInfo Nullable HubServiceInfo representing the service associated with this session
+     */
+    void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator, in @nullable HubServiceInfo serviceInfo);
+
+    /**
+     * 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..4688439
--- /dev/null
+++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java
@@ -0,0 +1,82 @@
+/*
+ * 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.Nullable;
+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
+     * @param serviceInfo The {@link HubServiceInfo} object representing the service associated with
+     *     this session. Null indicates that there is no service associated with this session.
+     */
+    @NonNull
+    HubEndpointSessionResult onSessionOpenRequest(
+            @NonNull HubEndpointInfo requester, @Nullable HubServiceInfo serviceInfo);
+
+    /**
+     * 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 e6a1640..25327a9 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -61,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;
@@ -102,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.
@@ -1613,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.
@@ -1674,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 be710b1..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;
@@ -188,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 {
@@ -1514,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);
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 399184c..68b6cfc 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -470,6 +470,31 @@
      */
     public abstract boolean isDisplayReadyForMirroring(int displayId);
 
+
+    /**
+     * Used by the window manager to override the per-display screen brightness based on the
+     * current foreground activity.
+     *
+     * The key of the array is the displayId. If a displayId is missing from the array, this is
+     * equivalent to clearing any existing brightness overrides for that display.
+     *
+     * This method must only be called by the window manager.
+     */
+    public abstract void setScreenBrightnessOverrideFromWindowManager(
+            SparseArray<DisplayBrightnessOverrideRequest> brightnessOverrides);
+
+    /**
+     * Describes a request for overriding the brightness of a single display.
+     */
+    public static class DisplayBrightnessOverrideRequest {
+        // An override of the screen brightness.
+        // Set to PowerManager.BRIGHTNESS_INVALID if there's no override.
+        public float brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
+        // Tag used to identify the app window requesting the brightness override.
+        public CharSequence tag;
+    }
+
     /**
      * Describes the requested power state of the display.
      *
@@ -505,11 +530,11 @@
         // nearby, turning it off temporarily until the object is moved away.
         public boolean useProximitySensor;
 
-        // An override of the screen brightness.
+        // A global override of the screen brightness, applied to all displays.
         // Set to PowerManager.BRIGHTNESS_INVALID if there's no override.
         public float screenBrightnessOverride;
 
-        // Tag used to identify the app window requesting the brightness override.
+        // Tag used to identify the reason for the global brightness override.
         public CharSequence screenBrightnessOverrideTag;
 
         // An override of the screen auto-brightness adjustment factor in the range -1 (dimmer) to
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 3284761..ed510e4 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -281,4 +281,6 @@
     AidlInputGestureData[] getCustomInputGestures(int userId, int tag);
 
     AidlInputGestureData[] getAppLaunchBookmarks();
+
+    void resetLockedModifierState();
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f824192..10224c1 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -260,7 +260,7 @@
     }
 
     /**
-     * Custom input gesture error: Input gesture already exists
+     * Custom input gesture result success
      *
      * @hide
      */
@@ -1590,6 +1590,21 @@
     }
 
     /**
+     * Resets locked modifier state (i.e.. Caps Lock, Num Lock, Scroll Lock state)
+     *
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+    public void resetLockedModifierState() {
+        try {
+            mIm.resetLockedModifierState();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * A callback used to be notified about battery state changes for an input device. The
      * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the
      * listener is successfully registered to provide the initial battery state of the device.
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/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 494bfc9..426cd69f 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -34,6 +34,11 @@
 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.HubServiceInfo;
+import android.hardware.contexthub.IHubEndpointLifecycleCallback;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
@@ -42,6 +47,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 +685,65 @@
     }
 
     /**
+     * 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) {
+        // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
+        //  timing.
+        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();
+        }
+    }
+
+    /**
+     * Find a list of endpoints that provides a specific service.
+     *
+     * @param serviceDescriptor Statically generated ID for an endpoint.
+     * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery.
+     * @throws IllegalArgumentException if the serviceDescriptor is empty/null.
+     */
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @NonNull
+    public List<HubDiscoveryInfo> findEndpoints(@NonNull String serviceDescriptor) {
+        // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load
+        //  timing.
+        if (serviceDescriptor.isBlank()) {
+            throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor);
+        }
+        try {
+            List<HubEndpointInfo> endpointInfos =
+                    mService.findEndpointsWithService(serviceDescriptor);
+            List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size());
+            // Wrap with result type
+            for (HubEndpointInfo endpointInfo : endpointInfos) {
+                for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) {
+                    if (serviceInfo.getServiceDescriptor().equals(serviceDescriptor)) {
+                        results.add(new HubDiscoveryInfo(endpointInfo, serviceInfo));
+                    }
+                }
+            }
+            return results;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set a callback to receive messages from the context hub
      *
      * @param callback Callback object
@@ -1010,6 +1075,80 @@
     }
 
     /**
+     * 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) without specifying a
+     * service.
+     *
+     * <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, null);
+    }
+
+    /**
+     * Use a registered endpoint to connect to another endpoint (destination) for a service
+     * described by a {@link HubServiceInfo} object.
+     *
+     * <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)}).
+     * @param serviceInfo {@link HubServiceInfo} object that describes the service associated with
+     *     this session. The information will be sent to the destination as part of open request.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+    public void openSession(
+            @NonNull HubEndpoint hubEndpoint,
+            @NonNull HubEndpointInfo destination,
+            @NonNull HubServiceInfo serviceInfo) {
+        hubEndpoint.openSession(destination, serviceInfo);
+    }
+
+    /**
+     * 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 +1307,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..f9f41244 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,16 @@
     // Enables or disables test mode
     @EnforcePermission("ACCESS_CONTEXT_HUB")
     boolean setTestMode(in boolean enable);
+
+    // Finds all endpoints that has a specific ID
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    List<HubEndpointInfo> findEndpoints(long endpointId);
+
+    // Finds all endpoints that has a specific service
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    List<HubEndpointInfo> findEndpointsWithService(String service);
+
+    // 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/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 26308f6..4bc5bd2 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -16,9 +16,6 @@
 
 package android.inputmethodservice;
 
-import static android.view.inputmethod.Flags.FLAG_VERIFY_KEY_EVENT;
-
-import android.annotation.FlaggedApi;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -196,12 +193,6 @@
             }
         }
 
-        @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
-        @Override
-        public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
-            return AbstractInputMethodService.this.onShouldVerifyKeyEvent(event);
-        }
-
         /**
          * Take care of dispatching incoming trackball events to the appropriate
          * callbacks on the service, and tell the client when this is done.
@@ -317,14 +308,6 @@
         return false;
     }
 
-    /**
-     * @see InputMethodService#onShouldVerifyKeyEvent(KeyEvent)
-     */
-    @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
-    public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event) {
-        return false;
-    }
-
     /** @hide */
     @Override
     public final int getWindowType() {
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 9b37533..62b131a 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -16,16 +16,12 @@
 
 package android.inputmethodservice;
 
-import static android.view.inputmethod.Flags.verifyKeyEvent;
-
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Rect;
-import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.Message;
-import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.InputChannel;
@@ -45,8 +41,6 @@
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
-import java.util.Objects;
-
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
@@ -62,7 +56,6 @@
     private static final int DO_REMOVE_IME_SURFACE = 130;
     private static final int DO_FINISH_INPUT = 140;
     private static final int DO_INVALIDATE_INPUT = 150;
-    private final Context mContext;
 
 
     @UnsupportedAppUsage
@@ -73,7 +66,6 @@
 
     public IInputMethodSessionWrapper(Context context,
             InputMethodSession inputMethodSession, InputChannel channel) {
-        mContext = context;
         mCaller = new HandlerCaller(context, null,
                 this, true /*asyncHandler*/);
         mInputMethodSession = inputMethodSession;
@@ -241,8 +233,6 @@
     }
     private final class ImeInputEventReceiver extends InputEventReceiver
             implements InputMethodSession.EventCallback {
-        // Time after which a KeyEvent is invalid
-        private static final long KEY_EVENT_ALLOW_PERIOD_MS = 100L;
         private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
 
         public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -257,23 +247,10 @@
                 return;
             }
 
-            if (event instanceof KeyEvent keyEvent && needsVerification(keyEvent)) {
-                // any KeyEvent with modifiers (e.g. Ctrl/Alt/Fn) must be verified that
-                // they originated from system.
-                InputManager im = mContext.getSystemService(InputManager.class);
-                Objects.requireNonNull(im);
-                final long age = SystemClock.uptimeMillis() - keyEvent.getEventTime();
-                if (age >= KEY_EVENT_ALLOW_PERIOD_MS && im.verifyInputEvent(keyEvent) == null) {
-                    Log.w(TAG, "Unverified or Invalid KeyEvent injected into IME. Dropping "
-                            + keyEvent);
-                    finishInputEvent(event, false /* handled */);
-                    return;
-                }
-            }
-
             final int seq = event.getSequenceNumber();
             mPendingEvents.put(seq, event);
-            if (event instanceof KeyEvent keyEvent) {
+            if (event instanceof KeyEvent) {
+                KeyEvent keyEvent = (KeyEvent)event;
                 mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
             } else {
                 MotionEvent motionEvent = (MotionEvent)event;
@@ -294,21 +271,5 @@
                 finishInputEvent(event, handled);
             }
         }
-
-        private boolean hasKeyModifiers(KeyEvent event) {
-            if (event.hasNoModifiers()) {
-                return false;
-            }
-            return event.hasModifiers(KeyEvent.META_CTRL_ON)
-                    || event.hasModifiers(KeyEvent.META_ALT_ON)
-                    || event.hasModifiers(KeyEvent.KEYCODE_FUNCTION);
-        }
-
-        private boolean needsVerification(KeyEvent event) {
-            //TODO(b/331730488): Handle a11y events as well.
-            return verifyKeyEvent()
-                    && (hasKeyModifiers(event)
-                            || mInputMethodSession.onShouldVerifyKeyEvent(event));
-        }
     }
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a8fde4a..dadb5c38 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -56,7 +56,6 @@
 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.FLAG_VERIFY_KEY_EVENT;
 import static android.view.inputmethod.Flags.ctrlShiftShortcut;
 import static android.view.inputmethod.Flags.predictiveBackIme;
 
@@ -3736,23 +3735,6 @@
     }
 
     /**
-     * Received by the IME before dispatch to {@link #onKeyDown(int, KeyEvent)} to let the system
-     * know if the {@link KeyEvent} needs to be verified that it originated from the system.
-     * {@link KeyEvent}s may originate from outside of the system and any sensitive keys should be
-     * marked for verification. One example of this could be using key shortcuts for switching to
-     * another IME.
-     *
-     * @param keyEvent the event that may need verification.
-     * @return {@code true} if {@link KeyEvent} should have its HMAC verified before dispatch,
-     * {@code false} otherwise.
-     */
-    @FlaggedApi(FLAG_VERIFY_KEY_EVENT)
-    @Override
-    public boolean onShouldVerifyKeyEvent(@NonNull KeyEvent keyEvent) {
-        return false;
-    }
-
-    /**
      * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
      * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
      * the event).
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/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 3b5a99e..01222cd 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -36,6 +36,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -651,28 +652,39 @@
     private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags);
 
     /**
-     * This list is to hold strong reference to the frozen state callbacks. The callbacks are only
-     * weakly referenced by JNI so the strong references here are needed to keep the callbacks
-     * around until the proxy is GC'ed.
+     * This map is to hold strong reference to the frozen state callbacks.
+     *
+     * The callbacks are only weakly referenced by JNI so the strong references here are needed to
+     * keep the callbacks around until the proxy is GC'ed.
+     *
+     * The key is the original callback passed into {@link #addFrozenStateChangeCallback}. The value
+     * is the wrapped callback created in {@link #addFrozenStateChangeCallback} to dispatch the
+     * calls on the desired executor.
      */
-    private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
-            Collections.synchronizedList(new ArrayList<>());
+    private Map<FrozenStateChangeCallback, FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
+            Collections.synchronizedMap(new HashMap<>());
 
     /**
      * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
      */
-    public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+    public void addFrozenStateChangeCallback(Executor executor, FrozenStateChangeCallback callback)
             throws RemoteException {
-        addFrozenStateChangeCallbackNative(callback);
-        mFrozenStateChangeCallbacks.add(callback);
+        FrozenStateChangeCallback wrappedCallback = (who, state) ->
+                executor.execute(() -> callback.onFrozenStateChanged(who, state));
+        addFrozenStateChangeCallbackNative(wrappedCallback);
+        mFrozenStateChangeCallbacks.put(callback, wrappedCallback);
     }
 
     /**
      * See {@link IBinder#removeFrozenStateChangeCallback}
      */
-    public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
-        mFrozenStateChangeCallbacks.remove(callback);
-        return removeFrozenStateChangeCallbackNative(callback);
+    public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+            throws IllegalArgumentException {
+        FrozenStateChangeCallback wrappedCallback = mFrozenStateChangeCallbacks.remove(callback);
+        if (wrappedCallback == null) {
+            throw new IllegalArgumentException("callback not found");
+        }
+        return removeFrozenStateChangeCallbackNative(wrappedCallback);
     }
 
     private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 172a994f..4c9f08d 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -20,6 +20,7 @@
 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;
@@ -32,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;
@@ -118,11 +118,8 @@
         mUseConcurrent = UserHandle.isCore(Process.myUid());
         // Even then, we don't use it if instrumentation is loaded as it breaks some
         // platform tests.
-        final ActivityThread activityThread = ActivityThread.currentActivityThread();
-        if (activityThread != null) {
-            final Instrumentation instrumentation = activityThread.getInstrumentation();
-            mUseConcurrent &= instrumentation == null || !instrumentation.isInstrumenting();
-        }
+        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.
 
@@ -130,6 +127,19 @@
         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/IBinder.java b/core/java/android/os/IBinder.java
index a997f4c..8cfd324 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -25,6 +26,7 @@
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
 
 /**
  * Base interface for a remotable object, the core part of a lightweight
@@ -397,12 +399,31 @@
         @interface State {
         }
 
+        /**
+         * Represents the frozen state of the remote process.
+         *
+         * While in this state, the remote process won't be able to receive and handle a
+         * transaction. Therefore, any asynchronous transactions will be buffered and delivered when
+         * the process is unfrozen, and any synchronous transactions will result in an error.
+         *
+         * Buffered transactions may be stale by the time that the process is unfrozen and handles
+         * them. To avoid overwhelming the remote process with stale events or overflowing their
+         * buffers, it's best to avoid sending binder transactions to a frozen process.
+         */
         int STATE_FROZEN = 0;
+
+        /**
+         * Represents the unfrozen state of the remote process.
+         *
+         * In this state, the process hosting the object can execute and is not restricted
+         * by the freezer from using the CPU or responding to binder transactions.
+         */
         int STATE_UNFROZEN = 1;
 
         /**
          * Interface for receiving a callback when the process hosting an IBinder
          * has changed its frozen state.
+         *
          * @param who The IBinder whose hosting process has changed state.
          * @param state The latest state.
          */
@@ -427,16 +448,32 @@
      * <p>You will only receive state change notifications for remote binders, as local binders by
      * definition can't be frozen without you being frozen too.</p>
      *
+     * @param executor The executor on which to run the callback.
+     * @param callback The callback used to deliver state change notifications.
+     *
      * <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
      * this feature.
      */
     @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
-    default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
+    default void addFrozenStateChangeCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull FrozenStateChangeCallback callback)
             throws RemoteException {
         throw new UnsupportedOperationException();
     }
 
     /**
+     * Same as {@link #addFrozenStateChangeCallback(Executor, FrozenStateChangeCallback)} except
+     * that callbacks are invoked on a binder thread.
+     *
+     * @hide
+     */
+    default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
+            throws RemoteException {
+        addFrozenStateChangeCallback(Runnable::run, callback);
+    }
+
+    /**
      * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
      * the hosting process changes its frozen state.
      */
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 24e1d66..e63b664 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -128,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/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 29ccb85..9435f4d 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -98,18 +98,6 @@
     }
 
     /**
-     * Used by the window manager to override the screen brightness based on the
-     * current foreground activity.
-     *
-     * This method must only be called by the window manager.
-     *
-     * @param brightness The overridden brightness, or Float.NaN to disable the override.
-     * @param tag Source identifier of the app window that requests the override.
-     */
-    public abstract void setScreenBrightnessOverrideFromWindowManager(
-            float brightness, CharSequence tag);
-
-    /**
      * Used by the window manager to override the user activity timeout based on the
      * current foreground activity.  It can only be used to make the timeout shorter
      * than usual, not longer.
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 91c482fa..d5630fd 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -29,6 +30,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executor;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -134,6 +136,7 @@
 
     private final @FrozenCalleePolicy int mFrozenCalleePolicy;
     private final int mMaxQueueSize;
+    private final Executor mExecutor;
 
     private final class Interface implements IBinder.DeathRecipient,
             IBinder.FrozenStateChangeCallback {
@@ -197,7 +200,7 @@
         void maybeSubscribeToFrozenCallback() throws RemoteException {
             if (mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
                 try {
-                    mBinder.addFrozenStateChangeCallback(this);
+                    mBinder.addFrozenStateChangeCallback(mExecutor, this);
                 } catch (UnsupportedOperationException e) {
                     // The kernel does not support frozen notifications. In this case we want to
                     // silently fall back to FROZEN_CALLEE_POLICY_UNSET. This is done by simply
@@ -237,6 +240,7 @@
         private @FrozenCalleePolicy int mFrozenCalleePolicy;
         private int mMaxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
         private InterfaceDiedCallback mInterfaceDiedCallback;
+        private Executor mExecutor;
 
         /**
          * Creates a Builder for {@link RemoteCallbackList}.
@@ -285,6 +289,18 @@
         }
 
         /**
+         * Sets the executor to be used when invoking callbacks asynchronously.
+         *
+         * This is only used when callbacks need to be invoked asynchronously, e.g. when the process
+         * hosting a callback becomes unfrozen. Callbacks that can be invoked immediately run on the
+         * same thread that calls {@link #broadcast} synchronously.
+         */
+        public @NonNull Builder setExecutor(@NonNull @CallbackExecutor Executor executor) {
+            mExecutor = executor;
+            return this;
+        }
+
+        /**
          * For notifying when the process hosting a callback interface has died.
          *
          * @param <E> The remote callback interface type.
@@ -308,15 +324,21 @@
          * @return The built {@link RemoteCallbackList} object.
          */
         public @NonNull RemoteCallbackList<E> build() {
+            Executor executor = mExecutor;
+            if (executor == null && mFrozenCalleePolicy != FROZEN_CALLEE_POLICY_UNSET) {
+                // TODO Throw an exception here once the existing API caller is updated to provide
+                // an executor.
+                executor = new HandlerExecutor(Handler.getMain());
+            }
             if (mInterfaceDiedCallback != null) {
-                return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize) {
+                return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor) {
                     @Override
                     public void onCallbackDied(E deadInterface, Object cookie) {
                         mInterfaceDiedCallback.onInterfaceDied(this, deadInterface, cookie);
                     }
                 };
             }
-            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize);
+            return new RemoteCallbackList<E>(mFrozenCalleePolicy, mMaxQueueSize, executor);
         }
     }
 
@@ -341,13 +363,23 @@
     }
 
     /**
+     * Returns the executor used when invoking callbacks asynchronously.
+     *
+     * @return The executor.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    public @Nullable Executor getExecutor() {
+        return mExecutor;
+    }
+
+    /**
      * Creates a RemoteCallbackList with {@link #FROZEN_CALLEE_POLICY_UNSET}. This is equivalent to
      * <pre>
      * new RemoteCallbackList.Build(RemoteCallbackList.FROZEN_CALLEE_POLICY_UNSET).build()
      * </pre>
      */
     public RemoteCallbackList() {
-        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE);
+        this(FROZEN_CALLEE_POLICY_UNSET, DEFAULT_MAX_QUEUE_SIZE, null);
     }
 
     /**
@@ -362,10 +394,14 @@
      * recipient's process is frozen. Once the limit is reached, the oldest callbacks would be
      * dropped to keep the size under limit. Ignored except for
      * {@link #FROZEN_CALLEE_POLICY_ENQUEUE_ALL}.
+     *
+     * @param executor The executor used when invoking callbacks asynchronously.
      */
-    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize) {
+    private RemoteCallbackList(@FrozenCalleePolicy int frozenCalleePolicy, int maxQueueSize,
+            @CallbackExecutor Executor executor) {
         mFrozenCalleePolicy = frozenCalleePolicy;
         mMaxQueueSize = maxQueueSize;
+        mExecutor = executor;
     }
 
     /**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 70cbc73..f6bc389 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1826,52 +1826,6 @@
     }
 
     /**
-     * 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);
-    }
-
-    /**
      * A builder for waveform effects described by its envelope.
      *
      * <p>Waveform effect envelopes are defined by one or more control points describing a target
@@ -1882,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)
@@ -1916,20 +1870,48 @@
      * {@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;
         }
 
         /**
@@ -1940,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
@@ -1963,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;
             }
 
@@ -1984,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/flags.aconfig b/core/java/android/os/flags.aconfig
index 118167d..2ef8764 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -194,6 +194,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."
diff --git a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
index f2ad7a4..afaab55 100644
--- a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
+++ b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java
@@ -34,11 +34,11 @@
  * </ul>
  *
  * <p>This information can be used to help construct waveform envelope effects with
- * {@link VibrationEffect#startWaveformEnvelope()}. When designing these effects, it is also
+ * {@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#startWaveformEnvelope()
+ * @see VibrationEffect.WaveformEnvelopeBuilder
  * @see VibratorFrequencyProfile
  */
 @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 6264fbb..b5a822b 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -383,7 +383,7 @@
     bug: "363318732"
 }
 
-flag{
+flag {
     name: "note_op_batching_enabled"
     is_fixed_read_only: true
     is_exported: true
@@ -399,4 +399,22 @@
     namespace: "supervision"
     description: "This flag is used to enable all the remaining permissions required to the supervision role"
     bug: "367333883"
-}
\ No newline at end of file
+}
+
+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"
+}
+
+flag {
+    name: "check_op_overload_api_enabled"
+    is_exported: true
+    is_fixed_read_only: true
+    namespace: "permissions"
+    description: "Add new checkOp APIs that accept attributionTag"
+    bug: "240617242"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d2a20b6..a35c9c1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6395,27 +6395,6 @@
         public static final String SCREEN_FLASH_NOTIFICATION_COLOR =
                 "screen_flash_notification_color_global";
 
-
-        /**
-         * A semi-colon separated list of Bluetooth hearing devices' local ambient volume.
-         * Each entry is encoded as a key=value list, separated by commas. Ex:
-         *
-         * "addr=XX:XX:XX:00:11,ambient=20,group_ambient=30;addr=XX:XX:XX:00:22,ambient=50"
-         *
-         * The following keys are supported:
-         * <pre>
-         * addr                 (String)
-         * ambient              (int)
-         * group_ambient        (int)
-         * control_expanded     (boolean)
-         * </pre>
-         *
-         * Each entry must contains "addr" attribute, otherwise it'll be ignored.
-         * @hide
-         */
-        public static final String HEARING_DEVICE_LOCAL_AMBIENT_VOLUME =
-                "hearing_device_local_ambient_volume";
-
         /**
          * IMPORTANT: If you add a new public settings you also have to add it to
          * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
@@ -6560,7 +6539,6 @@
             PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
             PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
             PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
-            PRIVATE_SETTINGS.add(HEARING_DEVICE_LOCAL_AMBIENT_VOLUME);
         }
 
         /**
@@ -18138,6 +18116,44 @@
         public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
 
         /**
+         * A semi-colon separated list of Bluetooth hearing devices' local ambient volume data.
+         * Each entry is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "addr=XX:XX:XX:00:11,ambient=20,group_ambient=30;addr=XX:XX:XX:00:22,ambient=50"
+         *
+         * The following keys are supported:
+         * <pre>
+         * addr                 (String)
+         * ambient              (int)
+         * group_ambient        (int)
+         * control_expanded     (boolean)
+         * </pre>
+         *
+         * Each entry must contains "addr" attribute, otherwise it'll be ignored.
+         * @hide
+         */
+        public static final String HEARING_DEVICE_LOCAL_AMBIENT_VOLUME =
+                "hearing_device_local_ambient_volume";
+
+        /**
+         * A semi-colon separated list of Bluetooth hearing devices' notification data.
+         * Each entry is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "addr=XX:XX:XX:00:11,input_changes=1"
+         *
+         * The following keys are supported:
+         * <pre>
+         * addr                 (String)
+         * input_changes        (boolean)
+         * </pre>
+         *
+         * Each entry must contains "addr" attribute, otherwise it'll be ignored.
+         * @hide
+         */
+        public static final String HEARING_DEVICE_LOCAL_NOTIFICATION =
+                "hearing_device_local_notification";
+
+        /**
          * Global settings that shouldn't be persisted.
          *
          * @hide
diff --git a/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java
new file mode 100644
index 0000000..75abd5f
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/AuthenticationPolicyManager.java
@@ -0,0 +1,237 @@
+/*
+ * 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.authenticationpolicy;
+
+import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+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 java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * AuthenticationPolicyManager is a centralized interface for managing authentication related
+ * policies on the device. This includes device locking capabilities to protect users in "at risk"
+ * environments.
+ *
+ * AuthenticationPolicyManager is designed to protect Android users by integrating with apps and
+ * key system components, such as the lock screen. It is not related to enterprise control surfaces
+ * and does not offer additional administrative controls.
+ *
+ * <p>
+ * To use this class, call {@link #enableSecureLockDevice} to enable secure lock on the device.
+ * This will require the caller to have the
+ * {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
+ *
+ * <p>
+ * To disable secure lock on the device, call {@link #disableSecureLockDevice}. This will require
+ * the caller to have the {@link android.Manifest.permission#MANAGE_SECURE_LOCK_DEVICE} permission.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+@SystemService(Context.AUTHENTICATION_POLICY_SERVICE)
+public final class AuthenticationPolicyManager {
+    private static final String TAG = "AuthenticationPolicyManager";
+
+    @NonNull private final IAuthenticationPolicyService mAuthenticationPolicyService;
+    @NonNull private final Context mContext;
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice} and {@link
+     * #disableSecureLockDevice}.
+     *
+     * Secure lock device request status unknown.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_UNKNOWN = 0;
+
+    /**
+     * Success result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+     *
+     * Secure lock device request successful.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int SUCCESS = 1;
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+     *
+     * Secure lock device is unsupported.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_UNSUPPORTED = 2;
+
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+     *
+     * Invalid secure lock device request params provided.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_INVALID_PARAMS = 3;
+
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+     *
+     * Secure lock device is unavailable because there are no biometrics enrolled on the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_NO_BIOMETRICS_ENROLLED = 4;
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice} and {@link #disableSecureLockDevice}.
+     *
+     * Secure lock device is unavailable because the device has no biometric hardware or the
+     * biometric sensors do not meet
+     * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_INSUFFICIENT_BIOMETRICS = 5;
+
+    /**
+     * Error result code for {@link #enableSecureLockDevice}.
+     *
+     * Secure lock is already enabled.
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public static final int ERROR_ALREADY_ENABLED = 6;
+
+    /**
+     * Communicates the current status of a request to enable secure lock on the device.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"ENABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = {
+            ERROR_UNKNOWN,
+            SUCCESS,
+            ERROR_UNSUPPORTED,
+            ERROR_INVALID_PARAMS,
+            ERROR_NO_BIOMETRICS_ENROLLED,
+            ERROR_INSUFFICIENT_BIOMETRICS,
+            ERROR_ALREADY_ENABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EnableSecureLockDeviceRequestStatus {}
+
+    /**
+     * Communicates the current status of a request to disable secure lock on the device.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"DISABLE_SECURE_LOCK_DEVICE_STATUS_"}, value = {
+            ERROR_UNKNOWN,
+            SUCCESS,
+            ERROR_UNSUPPORTED,
+            ERROR_INVALID_PARAMS,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisableSecureLockDeviceRequestStatus {}
+
+    /** @hide */
+    public AuthenticationPolicyManager(@NonNull Context context,
+            @NonNull IAuthenticationPolicyService authenticationPolicyService) {
+        mContext = context;
+        mAuthenticationPolicyService = authenticationPolicyService;
+    }
+
+    /**
+     * Called by a privileged component to remotely enable secure lock on the device.
+     *
+     * Secure lock is an enhanced security state that restricts access to sensitive data (app
+     * notifications, widgets, quick settings, assistant, etc) and requires multi-factor
+     * authentication for device entry, such as
+     * {@link android.hardware.biometrics.BiometricManager.Authenticators#DEVICE_CREDENTIAL} and
+     * {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_STRONG}.
+     *
+     * If secure lock is already enabled when this method is called, it will return
+     * {@link ERROR_ALREADY_ENABLED}.
+     *
+     * @param params EnableSecureLockDeviceParams for caller to supply params related to the secure
+     *               lock device request
+     * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the secure lock
+     * device request
+     *
+     * @hide
+     */
+    @EnableSecureLockDeviceRequestStatus
+    @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public int enableSecureLockDevice(@NonNull EnableSecureLockDeviceParams params) {
+        try {
+            return mAuthenticationPolicyService.enableSecureLockDevice(params);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Called by a privileged component to disable secure lock on the device.
+     *
+     * If secure lock is already disabled when this method is called, it will return
+     * {@link SUCCESS}.
+     *
+     * @param params @DisableSecureLockDeviceParams for caller to supply params related to the
+     *               secure lock device request
+     * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the secure lock
+     * device request
+     *
+     * @hide
+     */
+    @DisableSecureLockDeviceRequestStatus
+    @RequiresPermission(MANAGE_SECURE_LOCK_DEVICE)
+    @SystemApi
+    @FlaggedApi(FLAG_SECURE_LOCKDOWN)
+    public int disableSecureLockDevice(@NonNull DisableSecureLockDeviceParams params) {
+        try {
+            return mAuthenticationPolicyService.disableSecureLockDevice(params);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl
new file mode 100644
index 0000000..81f7726
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.authenticationpolicy;
+
+/**
+ * @hide
+ */
+parcelable DisableSecureLockDeviceParams;
\ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java
new file mode 100644
index 0000000..64a3f0f
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java
@@ -0,0 +1,82 @@
+/*
+ * 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.authenticationpolicy;
+
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Parameters related to a request to disable secure lock on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+public final class DisableSecureLockDeviceParams implements Parcelable {
+
+    /**
+     * Client message associated with the request to disable secure lock on the device. This message
+     * will be shown on the device when secure lock mode is disabled.
+     */
+    private final @NonNull String mMessage;
+
+    /**
+     * Creates DisableSecureLockDeviceParams with the given params.
+     *
+     * @param message Allows clients to pass in a message with information about the request to
+     *                disable secure lock on the device. This message will be shown to the user when
+     *                secure lock mode is disabled. If an empty string is provided, it will default
+     *                to a system-defined string (e.g. "Secure lock mode has been disabled.")
+     */
+    public DisableSecureLockDeviceParams(@NonNull String message) {
+        mMessage = message;
+    }
+
+    private DisableSecureLockDeviceParams(@NonNull Parcel in) {
+        mMessage = Objects.requireNonNull(in.readString8());
+    }
+
+    public static final @NonNull Creator<DisableSecureLockDeviceParams> CREATOR =
+            new Creator<DisableSecureLockDeviceParams>() {
+                @Override
+                public DisableSecureLockDeviceParams createFromParcel(Parcel in) {
+                    return new DisableSecureLockDeviceParams(in);
+                }
+
+                @Override
+                public DisableSecureLockDeviceParams[] newArray(int size) {
+                    return new DisableSecureLockDeviceParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mMessage);
+    }
+}
diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl
new file mode 100644
index 0000000..9e496f8
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.authenticationpolicy;
+
+/**
+ * @hide
+ */
+parcelable EnableSecureLockDeviceParams;
\ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java
new file mode 100644
index 0000000..1d72772
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java
@@ -0,0 +1,82 @@
+/*
+ * 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.authenticationpolicy;
+
+import static android.security.Flags.FLAG_SECURE_LOCKDOWN;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+
+/**
+ * Parameters related to a request to enable secure lock on the device.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_SECURE_LOCKDOWN)
+public final class EnableSecureLockDeviceParams implements Parcelable {
+
+    /**
+     * Client message associated with the request to enable secure lock on the device. This message
+     * will be shown on the device when secure lock mode is enabled.
+     */
+    private final @NonNull String mMessage;
+
+    /**
+     * Creates EnableSecureLockDeviceParams with the given params.
+     *
+     * @param message Allows clients to pass in a message with information about the request to
+     *                enable secure lock on the device. This message will be shown to the user when
+     *                secure lock mode is enabled. If an empty string is provided, it will default
+     *                to a system-defined string (e.g. "Device is securely locked remotely.")
+     */
+    public EnableSecureLockDeviceParams(@NonNull String message) {
+        mMessage = message;
+    }
+
+    private EnableSecureLockDeviceParams(@NonNull Parcel in) {
+        mMessage = Objects.requireNonNull(in.readString8());
+    }
+
+    public static final @NonNull Creator<EnableSecureLockDeviceParams> CREATOR =
+            new Creator<EnableSecureLockDeviceParams>() {
+                @Override
+                public EnableSecureLockDeviceParams createFromParcel(Parcel in) {
+                    return new EnableSecureLockDeviceParams(in);
+                }
+
+                @Override
+                public EnableSecureLockDeviceParams[] newArray(int size) {
+                    return new EnableSecureLockDeviceParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mMessage);
+    }
+}
diff --git a/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.aidl
new file mode 100644
index 0000000..5ad4534
--- /dev/null
+++ b/core/java/android/security/authenticationpolicy/IAuthenticationPolicyService.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.security.authenticationpolicy;
+
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+
+/**
+ * Communication channel from AuthenticationPolicyManager to AuthenticationPolicyService.
+ * @hide
+ */
+interface IAuthenticationPolicyService {
+    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
+    int enableSecureLockDevice(in EnableSecureLockDeviceParams params);
+
+    @EnforcePermission("MANAGE_SECURE_LOCK_DEVICE")
+    int disableSecureLockDevice(in DisableSecureLockDeviceParams params);
+}
\ No newline at end of file
diff --git a/core/java/android/security/authenticationpolicy/OWNERS b/core/java/android/security/authenticationpolicy/OWNERS
new file mode 100644
index 0000000..4310d1a
--- /dev/null
+++ b/core/java/android/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/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/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/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 24328eb..1388778 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -2532,7 +2532,7 @@
 
     /** Returns whether the rule id corresponds to an implicit rule. */
     public static boolean isImplicitRuleId(@NonNull String ruleId) {
-        return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX);
+        return ruleId != null && ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX);
     }
 
     private static int[] tryParseHourAndMinute(String value) {
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/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 1df3b43..c16a510 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -1712,6 +1712,15 @@
                 @NonNull NtnSignalStrength ntnSignalStrength) {
             // not supported on the deprecated interface - Use TelephonyCallback instead
         }
+
+        public final void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) {
+            // not supported on the deprecated interface - Use TelephonyCallback instead
+        }
+
+        public final void onCellularIdentifierDisclosedChanged(
+                CellularIdentifierDisclosure disclosure) {
+            // not supported on the deprecated interface - Use TelephonyCallback instead
+        }
     }
 
     private void log(String s) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 0d1dc46..2c585e6 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -705,6 +705,28 @@
     public static final int EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED = 45;
 
     /**
+     * Event for changes to mobile network ciphering algorithms.
+     * See {@link SecurityAlgorithmsListener#onSecurityAlgorithmsChanged}
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46;
+
+     /**
+      * Event for updates to sensitive device identifier disclosures (IMSI, IMEI, unciphered SUCI).
+      * See {@link CellularIdentifierDisclosedListener#onCellularIdentifierDisclosedChanged}
+      *
+      * @hide
+      */
+    @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47;
+
+    /**
      * @hide
      */
     @IntDef(prefix = {"EVENT_"}, value = {
@@ -752,7 +774,9 @@
             EVENT_CARRIER_ROAMING_NTN_MODE_CHANGED,
             EVENT_CARRIER_ROAMING_NTN_ELIGIBLE_STATE_CHANGED,
             EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED,
-            EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED
+            EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED,
+            EVENT_SECURITY_ALGORITHMS_CHANGED,
+            EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface TelephonyEvent {
@@ -1827,6 +1851,41 @@
     }
 
     /**
+     * Interface for CellularIdentifierDisclosedListener
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
+    public interface CellularIdentifierDisclosedListener {
+        /**
+         * Callback invoked when a device identifier (IMSI, IMEI, or unciphered SUCI)
+         * is disclosed over the network before a security context is established
+         * ("pre-authentication").
+         *
+         * @param disclosure details of the identifier disclosure
+         * See {@link CellularIdentifierDisclosure} for more details
+         */
+        void onCellularIdentifierDisclosedChanged(@NonNull CellularIdentifierDisclosure disclosure);
+    }
+
+    /**
+     * Interface for SecurityAlgorithmsListener
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS)
+    public interface SecurityAlgorithmsListener {
+        /**
+         * Callback invoked when the most recently reported security algorithms has changed,
+         * per a specified connection event.
+         *
+         * @param securityAlgorithmUpdate details of the security algorithm update
+         * See {@link SecurityAlgorithmUpdate} for more details
+         */
+        void onSecurityAlgorithmsChanged(@NonNull SecurityAlgorithmUpdate securityAlgorithmUpdate);
+    }
+
+    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      * <p>
@@ -2302,5 +2361,27 @@
                     () -> listener.onCarrierRoamingNtnSignalStrengthChanged(ntnSignalStrength)));
 
         }
+
+        public void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) {
+            if (!Flags.securityAlgorithmsUpdateIndications()) return;
+
+            SecurityAlgorithmsListener listener =
+                    (SecurityAlgorithmsListener) mTelephonyCallbackWeakRef.get();
+            if (listener == null) return;
+
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+                    () -> listener.onSecurityAlgorithmsChanged(update)));
+        }
+
+        public void onCellularIdentifierDisclosedChanged(CellularIdentifierDisclosure disclosure) {
+            if (!Flags.cellularIdentifierDisclosureIndications()) return;
+
+            CellularIdentifierDisclosedListener listener =
+                    (CellularIdentifierDisclosedListener) mTelephonyCallbackWeakRef.get();
+            if (listener == null) return;
+
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+                    () -> listener.onCellularIdentifierDisclosedChanged(disclosure)));
+        }
     }
 }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 90b0bb3..4ec429d 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -1154,6 +1154,40 @@
         }
     }
 
+   /**
+     * Notify external listeners that the radio security algorithms have changed.
+     * @param slotIndex for the phone object that got updated
+     * @param subId for which the security algorithm changed
+     * @param update details of the security algorithm update
+     * @hide
+     */
+    public void notifySecurityAlgorithmsChanged(
+            int slotIndex, int subId, SecurityAlgorithmUpdate update) {
+        try {
+            sRegistry.notifySecurityAlgorithmsChanged(slotIndex, subId, update);
+        } catch (RemoteException ex) {
+            // system server crash
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Notify external listeners of a new cellular identifier disclosure change.
+     * @param slotIndex for the phone object that the disclosure applies to
+     * @param subId for which the disclosure applies to
+     * @param disclosure details of the identifier disclosure
+     * @hide
+     */
+    public void notifyCellularIdentifierDisclosedChanged(
+            int slotIndex, int subId, CellularIdentifierDisclosure disclosure) {
+        try {
+            sRegistry.notifyCellularIdentifierDisclosedChanged(slotIndex, subId, disclosure);
+        } catch (RemoteException ex) {
+            // system server crash
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Processes potential event changes from the provided {@link TelephonyCallback}.
      *
@@ -1313,6 +1347,15 @@
             eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED);
             eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED);
         }
+
+        if (telephonyCallback instanceof TelephonyCallback.CellularIdentifierDisclosedListener) {
+            eventList.add(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED);
+        }
+
+        if (telephonyCallback instanceof TelephonyCallback.SecurityAlgorithmsListener) {
+            eventList.add(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED);
+        }
+
         return eventList;
     }
 
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/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 5a71282..8cb96ae 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -930,8 +930,8 @@
             // of the next vsync event.
             int totalFrameDelays = mBufferStuffingData.numberFrameDelays
                     + mBufferStuffingData.numberWaitsForNextVsync + 1;
-            long vsyncsSinceLastCallback =
-                    (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos;
+            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.
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 5a28d5f..80ae3c3 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -437,16 +437,16 @@
         }
     }
 
-  /**
-   * Return whether the quick scale gesture, in which the user performs a double tap followed by a
-   * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
-   */
+    /**
+     * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+     * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+     */
     public boolean isQuickScaleEnabled() {
         return mQuickScaleEnabled;
     }
 
     /**
-     * Sets whether the associates {@link OnScaleGestureListener} should receive
+     * Sets whether the associated {@link OnScaleGestureListener} should receive
      * onScale callbacks when the user uses a stylus and presses the button.
      * Note that this is enabled by default if the app targets API 23 and newer.
      *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e50662a..19d3dc4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2516,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)));
+            }
         }
     }
 
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/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index 0f48f12..4f48cb6 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -16,7 +16,6 @@
 
 package android.view.inputmethod;
 
-import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
 import android.os.Bundle;
@@ -126,11 +125,6 @@
     public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback);
 
     /**
-     * @hide
-     */
-    boolean onShouldVerifyKeyEvent(@NonNull KeyEvent event);
-
-    /**
      * This method is called when there is a track ball event.
      *
      * <p>
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index 63f8c80..deaf957 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -177,9 +177,10 @@
 }
 
 flag {
-  name: "verify_key_event"
+  name: "adaptive_handwriting_bounds"
+  is_exported: true
   namespace: "input_method"
-  description: "Verify KeyEvents in IME"
-  bug: "331730488"
+  description: "Feature flag for adaptively increasing handwriting bounds."
+  bug: "350047836"
   is_fixed_read_only: true
-}
\ No newline at end of file
+}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index f474b34..c7d5a9f 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -253,6 +253,9 @@
     namespace: "lse_desktop_experience"
     description: "Enables enter desktop windowing transition & motion polish changes"
     bug: "369763947"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -260,6 +263,9 @@
     namespace: "lse_desktop_experience"
     description: "Enables exit desktop windowing transition & motion polish changes"
     bug: "353650462"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -343,6 +349,9 @@
     namespace: "lse_desktop_experience"
     description: "Enables custom transitions for alt-tab app launches in Desktop Mode."
     bug: "370735595"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -350,6 +359,9 @@
     namespace: "lse_desktop_experience"
     description: "Enables custom transitions for app launches in Desktop Mode."
     bug: "375992828"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
@@ -402,4 +414,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 96b9dc7..bb47707 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -29,14 +29,6 @@
 
 flag {
     namespace: "window_surfaces"
-    name: "secure_window_state"
-    description: "Move SC secure flag to WindowState level"
-    is_fixed_read_only: true
-    bug: "308662081"
-}
-
-flag {
-    namespace: "window_surfaces"
     name: "trusted_presentation_listener_for_window"
     is_exported: true
     description: "Enable trustedPresentationListener on windows public API"
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/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3ec7064..2cfc680 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -152,7 +152,7 @@
             in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
     int checkOperationRawForDevice(int code, int uid, String packageName,
             @nullable String attributionTag, int virtualDeviceId);
-    int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId);
+    int checkOperationForDevice(int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId);
     SyncNotedAppOp noteOperationForDevice(int code, int uid, String packageName,
             @nullable String attributionTag, int virtualDeviceId,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
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/policy/IDeviceLockedStateListener.aidl b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl
new file mode 100644
index 0000000..cc626f6
--- /dev/null
+++ b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.internal.policy;
+
+oneway interface IDeviceLockedStateListener {
+    void onDeviceLockedStateChanged(boolean isDeviceLocked);
+}
\ No newline at end of file
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/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 0e85e04..bf8a565 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -20,6 +20,7 @@
 import android.telephony.CallState;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.TelephonyDisplayInfo;
@@ -28,6 +29,7 @@
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.SecurityAlgorithmUpdate;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
@@ -87,4 +89,6 @@
     void onCarrierRoamingNtnEligibleStateChanged(in boolean eligible);
     void onCarrierRoamingNtnAvailableServicesChanged(in int[] availableServices);
     void onCarrierRoamingNtnSignalStrengthChanged(in NtnSignalStrength ntnSignalStrength);
+    void onSecurityAlgorithmsChanged(in SecurityAlgorithmUpdate update);
+    void onCellularIdentifierDisclosedChanged(in CellularIdentifierDisclosure disclosure);
 }
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0f268d5d..a296fbd1 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -23,6 +23,7 @@
 import android.telephony.CallQuality;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.ims.ImsReasonInfo;
@@ -30,6 +31,7 @@
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.SecurityAlgorithmUpdate;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
@@ -132,4 +134,7 @@
     void removeSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg);
     void notifySatelliteStateChanged(boolean isEnabled);
 
+    void notifySecurityAlgorithmsChanged(int phoneId, int subId, in SecurityAlgorithmUpdate update);
+    void notifyCellularIdentifierDisclosedChanged(
+            int phoneId, int subId, in CellularIdentifierDisclosure disclosure);
 }
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/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java
index 5fc61b0..c96e979 100644
--- a/core/java/com/android/internal/widget/NotificationRowIconView.java
+++ b/core/java/com/android/internal/widget/NotificationRowIconView.java
@@ -19,12 +19,7 @@
 import android.annotation.Nullable;
 import android.app.Flags;
 import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.util.AttributeSet;
@@ -41,7 +36,6 @@
 public class NotificationRowIconView extends CachingIconView {
     private NotificationIconProvider mIconProvider;
 
-    private boolean mApplyCircularCrop = false;
     private Drawable mAppIcon = null;
 
     // Padding, background and colors set on the view prior to being overridden when showing the app
@@ -221,84 +215,6 @@
         }
     }
 
-    @Nullable
-    @Override
-    Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
-        final Drawable original = super.loadSizeRestrictedIcon(icon);
-        final Drawable result;
-        if (mApplyCircularCrop) {
-            result = makeCircularDrawable(original);
-        } else {
-            result = original;
-        }
-
-        return result;
-    }
-
-    /**
-     * Enables circle crop that makes given image circular
-     */
-    @RemotableViewMethod(asyncImpl = "setApplyCircularCropAsync")
-    public void setApplyCircularCrop(boolean applyCircularCrop) {
-        mApplyCircularCrop = applyCircularCrop;
-    }
-
-    /**
-     * Async version of {@link NotificationRowIconView#setApplyCircularCrop}
-     */
-    public Runnable setApplyCircularCropAsync(boolean applyCircularCrop) {
-        mApplyCircularCrop = applyCircularCrop;
-        return () -> {
-        };
-    }
-
-    @Nullable
-    private Drawable makeCircularDrawable(@Nullable Drawable original) {
-        if (original == null) {
-            return original;
-        }
-
-        final Bitmap source = drawableToBitmap(original);
-
-        int size = Math.min(source.getWidth(), source.getHeight());
-
-        Bitmap squared = Bitmap.createScaledBitmap(source, size, size, /* filter= */ false);
-        Bitmap result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-
-        final Canvas canvas = new Canvas(result);
-        final Paint paint = new Paint();
-        paint.setShader(
-                new BitmapShader(squared, BitmapShader.TileMode.CLAMP,
-                        BitmapShader.TileMode.CLAMP));
-        paint.setAntiAlias(true);
-        float radius = size / 2f;
-        canvas.drawCircle(radius, radius, radius, paint);
-        return new BitmapDrawable(getResources(), result);
-    }
-
-    private static Bitmap drawableToBitmap(Drawable drawable) {
-        if (drawable instanceof BitmapDrawable bitmapDrawable) {
-            final Bitmap bitmap = bitmapDrawable.getBitmap();
-            if (bitmap.getConfig() == Bitmap.Config.HARDWARE) {
-                return bitmap.copy(Bitmap.Config.ARGB_8888, false);
-            } else {
-                return bitmap;
-            }
-        }
-
-        int width = drawable.getIntrinsicWidth();
-        width = width > 0 ? width : 1;
-        int height = drawable.getIntrinsicHeight();
-        height = height > 0 ? height : 1;
-
-        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-        drawable.draw(canvas);
-
-        return bitmap;
-    }
-
     /**
      * A provider that allows this view to verify whether it should use the app icon instead of the
      * icon provided to it via setImageIcon, as well as actually fetching the app icon. It should
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f9d00ed..5a18392 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -584,14 +584,23 @@
     return lpRecorder->setInputDevice(device_id) == NO_ERROR;
 }
 
-static jint android_media_AudioRecord_getRoutedDeviceId(
-                JNIEnv *env,  jobject thiz) {
-
+static jintArray android_media_AudioRecord_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
-    if (lpRecorder == 0) {
-        return 0;
+    if (lpRecorder == NULL) {
+        return NULL;
     }
-    return (jint)lpRecorder->getRoutedDeviceId();
+    DeviceIdVector deviceIds = lpRecorder->getRoutedDeviceIds();
+    jintArray result;
+    result = env->NewIntArray(deviceIds.size());
+    if (result == NULL) {
+        return NULL;
+    }
+    jint *values = env->GetIntArrayElements(result, 0);
+    for (unsigned int i = 0; i < deviceIds.size(); i++) {
+        values[i++] = static_cast<jint>(deviceIds[i]);
+    }
+    env->ReleaseIntArrayElements(result, values, 0);
+    return result;
 }
 
 // Enable and Disable Callback methods are synchronized on the Java side
@@ -821,8 +830,7 @@
         // name,               signature,  funcPtr
         {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
         {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
-        {"native_setup",
-         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
+        {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I",
          (void *)android_media_AudioRecord_setup},
         {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
         {"native_release", "()V", (void *)android_media_AudioRecord_release},
@@ -846,7 +854,7 @@
         {"native_getMetrics", "()Landroid/os/PersistableBundle;",
          (void *)android_media_AudioRecord_native_getMetrics},
         {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
-        {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+        {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioRecord_getRoutedDeviceIds},
         {"native_enableDeviceCallback", "()V",
          (void *)android_media_AudioRecord_enableDeviceCallback},
         {"native_disableDeviceCallback", "()V",
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_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1557f9e..5d4d1ce 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1190,15 +1190,23 @@
     }
     return lpTrack->setOutputDevice(device_id) == NO_ERROR;
 }
-
-static jint android_media_AudioTrack_getRoutedDeviceId(
-                JNIEnv *env,  jobject thiz) {
-
+static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
-        return 0;
+        return NULL;
     }
-    return (jint)lpTrack->getRoutedDeviceId();
+    DeviceIdVector deviceIds = lpTrack->getRoutedDeviceIds();
+    jintArray result;
+    result = env->NewIntArray(deviceIds.size());
+    if (result == NULL) {
+        return NULL;
+    }
+    jint *values = env->GetIntArrayElements(result, 0);
+    for (unsigned int i = 0; i < deviceIds.size(); i++) {
+        values[i++] = static_cast<jint>(deviceIds[i]);
+    }
+    env->ReleaseIntArrayElements(result, values, 0);
+    return result;
 }
 
 static void android_media_AudioTrack_enableDeviceCallback(
@@ -1503,7 +1511,7 @@
          (void *)android_media_AudioTrack_setAuxEffectSendLevel},
         {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
         {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
-        {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
+        {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioTrack_getRoutedDeviceIds},
         {"native_enableDeviceCallback", "()V",
          (void *)android_media_AudioTrack_enableDeviceCallback},
         {"native_disableDeviceCallback", "()V",
diff --git a/core/jni/android_media_DeviceCallback.cpp b/core/jni/android_media_DeviceCallback.cpp
index a1a0351..ccdf633 100644
--- a/core/jni/android_media_DeviceCallback.cpp
+++ b/core/jni/android_media_DeviceCallback.cpp
@@ -61,21 +61,20 @@
 }
 
 void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo,
-                                            audio_port_handle_t deviceId)
-{
+                                            const DeviceIdVector& deviceIds) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     if (env == NULL) {
         return;
     }
 
-    ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId);
-    env->CallStaticVoidMethod(mClass,
-                              mPostEventFromNative,
-                              mObject,
-                              AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL);
+    ALOGV("%s audioIo %d deviceIds %s", __FUNCTION__, audioIo, toString(deviceIds).c_str());
+    // Java should query the new device ids once it gets the event.
+    // TODO(b/378505346): Pass the deviceIds to Java to avoid race conditions.
+    env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+                              AUDIO_NATIVE_EVENT_ROUTING_CHANGE, 0 /*arg1*/, 0 /*arg2*/,
+                              NULL /*obj*/);
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred while notifying an event.");
         env->ExceptionClear();
     }
 }
-
diff --git a/core/jni/android_media_DeviceCallback.h b/core/jni/android_media_DeviceCallback.h
index 7ae788e..0c9ccc8 100644
--- a/core/jni/android_media_DeviceCallback.h
+++ b/core/jni/android_media_DeviceCallback.h
@@ -31,8 +31,7 @@
     JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, jmethodID postEventFromNative);
     ~JNIDeviceCallback();
 
-    virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
-                                     audio_port_handle_t deviceId);
+    virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, const DeviceIdVector& deviceIds);
 
 private:
     void sendEvent(int event);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1925b3a..593b982 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -2201,29 +2201,9 @@
             return false;
         }
 
-        // Compute the count of data items we'll actually forward to Java.
-        size_t count = 0;
-        if (mRemovedVsyncId <= 0) {
-            count = jankData.size();
-        } else {
-            for (const gui::JankData& frame : jankData) {
-                if (frame.frameVsyncId <= mRemovedVsyncId) {
-                    count++;
-                }
-            }
-        }
-
-        if (count == 0) {
-            return false;
-        }
-
-        jobjectArray jJankDataArray = env->NewObjectArray(count, gJankDataClassInfo.clazz, nullptr);
-        for (size_t i = 0, j = 0; i < jankData.size() && j < count; i++) {
-            // Filter any data for frames past our removal vsync.
-            if (mRemovedVsyncId > 0 && jankData[i].frameVsyncId > mRemovedVsyncId) {
-                continue;
-            }
-
+        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.
             int sfJankType = jankData[i].jankType;
@@ -2250,7 +2230,7 @@
                                    jankData[i].frameVsyncId, javaJankType,
                                    jankData[i].frameIntervalNs, jankData[i].scheduledAppFrameTimeNs,
                                    jankData[i].actualAppFrameTimeNs);
-            env->SetObjectArrayElement(jJankDataArray, j++, jJankData);
+            env->SetObjectArrayElement(jJankDataArray, i, jJankData);
             env->DeleteLocalRef(jJankData);
         }
 
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 0e4e22b..26e63bc 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -161,6 +161,7 @@
         "android.app.flags-aconfig",
         "android.appwidget.flags-aconfig",
         "android.content.pm.flags-aconfig",
+        "android.media.audio-aconfig",
         "android.provider.flags-aconfig",
         "camera_platform_flags",
         "android.net.platform.flags-aconfig",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3e0c120..8cc7b0b 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 -->
@@ -5497,7 +5587,8 @@
     <permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE"
         android:protectionLevel="signature" />
 
-    <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
+    <!-- Allows an application to subscribe to device locked and keyguard locked (i.e., showing)
+        state.
          <p>Protection level: signature|role
          <p>Intended for use by ROLE_ASSISTANT and signature apps only.
     -->
@@ -6401,6 +6492,15 @@
     <permission android:name="android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT"
         android:protectionLevel="signature|privileged|role" />
 
+    <!-- @SystemApi Allows an application to bypass concurrency restrictions while
+        recording audio. For example, apps with this permission can continue to record
+        while a voice call is active.</p>
+     @FlaggedApi(android.media.audio.Flags.FLAG_CONCURRENT_AUDIO_RECORD_BYPASS_PERMISSION)
+     @hide -->
+    <permission android:name="android.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION"
+        android:featureFlag="android.media.audio.concurrent_audio_record_bypass_permission"
+        android:protectionLevel="signature|privileged|role" />
+
     <!-- @SystemApi Allows an application to capture audio for hotword detection.
          <p>Not for use by third-party applications.</p>
          @hide -->
@@ -7844,7 +7944,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> -->
@@ -8536,6 +8660,17 @@
     <permission android:name="android.permission.SETUP_FSVERITY"
                 android:protectionLevel="signature|privileged"/>
 
+    <!-- @SystemApi
+        @FlaggedApi(android.security.Flags.FLAG_SECURE_LOCKDOWN)
+        Allows an application to lock down the device into an enhanced security state.
+        <p>Not for use by third-party applications.
+        <p>Protection level: signature|privileged
+        @hide
+    -->
+    <permission android:name="android.permission.MANAGE_SECURE_LOCK_DEVICE"
+        android:protectionLevel="signature|privileged"
+        android:featureFlag="android.security.secure_lockdown" />
+
     <!-- Allows app to enter trade-in-mode.
         <p>Protection level: signature|privileged
         @hide
@@ -8565,27 +8700,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/layout/notification_2025_template_heads_up_base.xml b/core/res/res/layout/notification_2025_template_heads_up_base.xml
new file mode 100644
index 0000000..e4ff835
--- /dev/null
+++ b/core/res/res/layout/notification_2025_template_heads_up_base.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2014 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:orientation="vertical"
+    android:clipChildren="false"
+    android:tag="headsUp"
+    >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:orientation="vertical"
+        >
+
+        <include
+            layout="@layout/notification_2025_template_collapsed_base"
+            android:id="@null"
+            />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-20dp"
+            android:clipChildren="false"
+            android:orientation="vertical"
+            >
+
+            <ViewStub
+                android:layout="@layout/notification_material_reply_text"
+                android:id="@+id/notification_material_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                />
+
+            <include
+                layout="@layout/notification_template_smart_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin"
+                />
+
+            <include layout="@layout/notification_material_action_list" />
+        </LinearLayout>
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
index 82920ba..149a5a9 100644
--- a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
+++ b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml
@@ -34,12 +34,14 @@
         android:maxDrawableWidth="@dimen/notification_icon_circle_size"
         android:maxDrawableHeight="@dimen/notification_icon_circle_size"
         />
-    <com.android.internal.widget.NotificationRowIconView
+    <com.android.internal.widget.CachingIconView
         android:id="@+id/conversation_icon"
         android:layout_width="@dimen/notification_icon_circle_size"
         android:layout_height="@dimen/notification_icon_circle_size"
         android:layout_gravity="center_vertical|start"
         android:layout_marginStart="@dimen/notification_icon_circle_start"
+        android:background="@drawable/notification_icon_circle"
+        android:clipToOutline="true"
         android:maxDrawableWidth="@dimen/notification_icon_circle_size"
         android:maxDrawableHeight="@dimen/notification_icon_circle_size"
         android:scaleType="centerCrop"
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/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 969ee2e..3f4ea2d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4205,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. -->
@@ -5898,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>
@@ -6567,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>
@@ -7212,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 a0bf89d..b0b87d1d 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -142,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 9dd3027..5a6b66c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2389,6 +2389,9 @@
   <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_heads_up_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" />
@@ -3140,9 +3143,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" />
@@ -3876,9 +3882,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" />
@@ -5311,73 +5317,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"/>
@@ -5679,8 +5703,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/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
index fe54aa8..945147d 100644
--- a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
+++ b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
@@ -18,6 +18,8 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -36,6 +38,7 @@
         @Override
         public void listenTo(IBinder binder) throws RemoteException {
             binder.addFrozenStateChangeCallback(
+                    new HandlerExecutor(Handler.getMain()),
                     (IBinder who, int state) -> mNotifications.offer(state));
         }
 
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index a2598f6..2fc72e1 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import static android.app.Flags.FLAG_PIC_CACHE_NULLS;
 import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID;
 import static android.app.PropertyInvalidatedCache.NONCE_UNSET;
 import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH;
@@ -229,7 +230,12 @@
         @Override
         public String apply(Integer qv) {
             mRecomputeCount += 1;
-            return "foo" + qv.toString();
+            // Special case for testing caches of nulls.  Integers in the range 30-40 return null.
+            if (qv >= 30 && qv < 40) {
+                return null;
+            } else {
+                return "foo" + qv.toString();
+            }
         }
 
         int getRecomputeCount() {
@@ -643,4 +649,35 @@
             Binder.restoreCallingWorkSource(token);
         }
     }
+
+    @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS)
+    @Test
+    public void testCachingNulls() {
+        TestCache cache = new TestCache(new Args(MODULE_TEST)
+                .maxEntries(4).api("testCachingNulls").cacheNulls(true),
+                new TestQuery());
+        cache.invalidateCache();
+        assertEquals("foo1", cache.query(1));
+        assertEquals("foo2", cache.query(2));
+        assertEquals(null, cache.query(30));
+        assertEquals(3, cache.getRecomputeCount());
+        assertEquals("foo1", cache.query(1));
+        assertEquals("foo2", cache.query(2));
+        assertEquals(null, cache.query(30));
+        assertEquals(3, cache.getRecomputeCount());
+
+        cache = new TestCache(new Args(MODULE_TEST)
+                .maxEntries(4).api("testCachingNulls").cacheNulls(false),
+                new TestQuery());
+        cache.invalidateCache();
+        assertEquals("foo1", cache.query(1));
+        assertEquals("foo2", cache.query(2));
+        assertEquals(null, cache.query(30));
+        assertEquals(3, cache.getRecomputeCount());
+        assertEquals("foo1", cache.query(1));
+        assertEquals("foo2", cache.query(2));
+        assertEquals(null, cache.query(30));
+        // The recompute is 4 because nulls were not cached.
+        assertEquals(4, cache.getRecomputeCount());
+    }
 }
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/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
index 0db49a7..ecacdb2 100644
--- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
+++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java
@@ -33,6 +33,7 @@
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.util.ArraySet;
 import android.util.PackageUtils;
 
@@ -61,6 +62,7 @@
 import java.util.Set;
 
 @Presubmit
+@RequiresFlagsEnabled(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
 public class ApkLiteParseUtilsTest {
 
     @Rule
diff --git a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
index 195a18a..523fe1a 100644
--- a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
+++ b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
@@ -200,7 +200,7 @@
         IBinder.FrozenStateChangeCallback callback =
                 (IBinder who, int state) -> results.offer(who);
         try {
-            binder.addFrozenStateChangeCallback(callback);
+            binder.addFrozenStateChangeCallback(new HandlerExecutor(Handler.getMain()), callback);
         } catch (UnsupportedOperationException e) {
             return;
         }
@@ -227,7 +227,7 @@
             final IBinder.FrozenStateChangeCallback callback =
                     (IBinder who, int state) ->
                             queue.offer(state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
-            binder.addFrozenStateChangeCallback(callback);
+            binder.addFrozenStateChangeCallback(new HandlerExecutor(Handler.getMain()), callback);
             return callback;
         } catch (UnsupportedOperationException e) {
             return null;
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 67de25e..7511887 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -42,6 +42,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.FileDescriptor;
+import java.util.concurrent.Executor;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -125,7 +126,7 @@
         }
 
         @Override
-        public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
+        public void addFrozenStateChangeCallback(Executor e, FrozenStateChangeCallback callback)
                 throws RemoteException {
         }
 
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..329e5de 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"/>
@@ -527,6 +533,8 @@
         <permission name="com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY" />
         <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
         <permission name="android.permission.LOCK_DEVICE" />
+        <!-- Permission required for AuthenticationPolicyManagerTest -->
+        <permission name="android.permission.MANAGE_SECURE_LOCK_DEVICE" />
         <!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
         <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
         <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
@@ -597,6 +605,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/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 55cda78..597a921 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -29,6 +29,7 @@
         <item name="android:navigationBarColor">@android:color/transparent</item>
         <item name="android:windowDrawsSystemBarBackgrounds">true</item>
         <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:windowIsTranslucent">true</item>
     </style>
 
     <style name="Animation.ForcedResizable" parent="@android:style/Animation">
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 823c533..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
@@ -274,11 +274,8 @@
     private final DragAndDropController mDragAndDropController;
     /** Used to send bubble events to launcher. */
     private Bubbles.BubbleStateListener mBubbleStateListener;
-    /**
-     * Used to track previous navigation mode to detect switch to buttons navigation. Set to
-     * true to switch the bubble bar to the opposite side for 3 nav buttons mode on device boot.
-     */
-    private boolean mIsPrevNavModeGestures = true;
+    /** Used to track previous navigation mode to detect switch to buttons navigation. */
+    private boolean mIsPrevNavModeGestures;
     /** Used to send updates to the views from {@link #mBubbleDataListener}. */
     private BubbleViewCallback mBubbleViewCallback;
 
@@ -360,6 +357,7 @@
             }
         };
         mExpandedViewManager = BubbleExpandedViewManager.fromBubbleController(this);
+        mIsPrevNavModeGestures = ContextUtils.isGestureNavigationMode(mContext);
     }
 
     private void registerOneHandedState(OneHandedController oneHanded) {
@@ -595,9 +593,9 @@
         if (mBubbleStateListener != null) {
             boolean isCurrentNavModeGestures = ContextUtils.isGestureNavigationMode(mContext);
             if (mIsPrevNavModeGestures && !isCurrentNavModeGestures) {
-                BubbleBarLocation bubbleBarLocation = ContextUtils.isRtl(mContext)
+                BubbleBarLocation navButtonsLocation = ContextUtils.isRtl(mContext)
                         ? BubbleBarLocation.RIGHT : BubbleBarLocation.LEFT;
-                mBubblePositioner.setBubbleBarLocation(bubbleBarLocation);
+                mBubblePositioner.setBubbleBarLocation(navButtonsLocation);
             }
             mIsPrevNavModeGestures = isCurrentNavModeGestures;
             BubbleBarUpdate update = mBubbleData.getInitialStateForBubbleBar();
@@ -2089,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);
             }
@@ -2101,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 e455985..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
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/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/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4db0be5..6fc6eb7 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
@@ -76,12 +71,13 @@
 import com.android.internal.protolog.ProtoLog
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
+import com.android.wm.shell.Flags.enableFlexibleSplit
+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
@@ -108,6 +104,7 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED
 import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
 import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
 import com.android.wm.shell.splitscreen.SplitScreenController
@@ -116,7 +113,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
@@ -134,6 +130,10 @@
 import java.util.concurrent.Executor
 import java.util.function.Consumer
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
+import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
+import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
+
 /** Handles moving tasks in and out of desktop */
 class DesktopTasksController(
     private val context: Context,
@@ -156,8 +156,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,
@@ -165,16 +163,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
@@ -207,6 +202,9 @@
     @VisibleForTesting
     var taskbarDesktopTaskListener: TaskbarDesktopTaskListener? = null
 
+    @VisibleForTesting
+    var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener? = null
+
     /** Task id of the task currently being dragged from fullscreen/split. */
     val draggingTaskId
         get() = dragToDesktopTransitionHandler.draggingTaskId
@@ -248,9 +246,6 @@
             }
         )
         dragAndDropController.addListener(this)
-        if (useKeyGestureEventHandler() && enableMoveToNextDisplayShortcut()) {
-            inputManager.registerKeyGestureEventHandler(this)
-        }
     }
 
     @VisibleForTesting
@@ -395,6 +390,7 @@
         )
         // TODO(343149901): Add DPI changes for task launch
         val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
         taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
         exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
         return true
@@ -424,6 +420,7 @@
         addMoveToDesktopChanges(wct, task)
 
         val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
+        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
         taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
         exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
     }
@@ -465,6 +462,9 @@
         val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
             wct, taskInfo.displayId)
         val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
+        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
+            DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt()
+        )
         transition?.let {
             taskIdToMinimize?.let { taskId -> addPendingMinimizeTransition(it, taskId) }
             exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
@@ -500,9 +500,7 @@
     ): ((IBinder) -> Unit)? {
         val taskId = taskInfo.taskId
         desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
-        if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
-            removeWallpaperActivity(wct)
-        }
+        performDesktopExitCleanupIfNeeded(taskId, wct)
         taskRepository.addClosingTask(displayId, taskId)
         taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
             doesAnyTaskRequireTaskbarRounding(
@@ -518,11 +516,7 @@
         val taskId = taskInfo.taskId
         val displayId = taskInfo.displayId
         val wct = WindowContainerTransaction()
-        if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
-            // Perform clean up of the desktop wallpaper activity if the minimized window task is
-            // the last active task.
-            removeWallpaperActivity(wct)
-        }
+        performDesktopExitCleanupIfNeeded(taskId, wct)
         // Notify immersive handler as it might need to exit immersive state.
         val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
 
@@ -591,6 +585,11 @@
                 position,
                 mOnAnimationFinishedCallback
             )
+
+        // handles case where we are moving to full screen without closing all DW tasks.
+        if (!taskRepository.isOnlyVisibleNonClosingTask(task.taskId)) {
+            desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+        }
     }
 
     /**
@@ -793,6 +792,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) }
@@ -871,9 +874,6 @@
             return
         }
 
-        desktopModeEventLogger.logTaskResizingStarted(
-            ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent, taskInfo, displayController
-        )
         toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent)
     }
 
@@ -961,13 +961,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,
@@ -993,7 +997,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,
@@ -1010,8 +1014,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,
@@ -1021,7 +1057,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"
             )
@@ -1046,9 +1082,6 @@
             } else {
                 ResizeTrigger.DRAG_RIGHT
             }
-            desktopModeEventLogger.logTaskResizingStarted(
-                resizeTrigger, motionEvent, taskInfo, displayController
-            )
             interactionJankMonitor.begin(
                 taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable"
             )
@@ -1064,6 +1097,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()
 
@@ -1204,6 +1240,21 @@
         }
     }
 
+    /**
+     * Remove wallpaper activity if task provided is last task and wallpaper activity token is not
+     * null
+     */
+    private fun performDesktopExitCleanupIfNeeded(taskId: Int, wct: WindowContainerTransaction) {
+        if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
+            return
+        }
+        desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
+        if (taskRepository.wallpaperActivityToken != null) {
+            removeWallpaperActivity(wct)
+        }
+    }
+
+
     fun releaseVisualIndicator() {
         val t = SurfaceControl.Transaction()
         visualIndicator?.releaseVisualIndicator(t)
@@ -1464,11 +1515,15 @@
             WINDOWING_MODE_MULTI_WINDOW -> {
                 val splitPosition = splitScreenController
                     .determineNewInstancePosition(callingTaskInfo)
+                // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+                //  specific cases in the future.
+                val splitIndex = if (enableFlexibleSplit())
+                    splitScreenController.determineNewInstanceIndex(callingTaskInfo) else
+                    SPLIT_INDEX_UNDEFINED
                 splitScreenController.startIntent(
                     launchIntent, context.userId, fillIn, splitPosition,
                     options.toBundle(), null /* hideTaskToken */,
-                    true /* forceLaunchNewTask */
-                )
+                    true /* forceLaunchNewTask */, splitIndex)
             }
             WINDOWING_MODE_FREEFORM -> {
                 val wct = WindowContainerTransaction()
@@ -1640,12 +1695,7 @@
             return null
 
         val wct = WindowContainerTransaction()
-        if (taskRepository.isOnlyVisibleNonClosingTask(task.taskId)
-            && taskRepository.wallpaperActivityToken != null
-        ) {
-            // Remove wallpaper activity when the last active task is removed
-            removeWallpaperActivity(wct)
-        }
+        performDesktopExitCleanupIfNeeded(task.taskId, wct)
 
         if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
             taskRepository.addClosingTask(task.displayId, task.taskId)
@@ -1736,10 +1786,8 @@
         if (useDesktopOverrideDensity()) {
             wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
         }
-        if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
-            // Remove wallpaper activity when leaving desktop mode
-            removeWallpaperActivity(wct)
-        }
+
+        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
     }
 
     private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -1768,10 +1816,8 @@
         // The task's density may have been overridden in freeform; revert it here as we don't
         // want it overridden in multi-window.
         wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
-        if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
-            // Remove wallpaper activity when leaving desktop mode
-            removeWallpaperActivity(wct)
-        }
+
+        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
     }
 
     /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
@@ -1835,26 +1881,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.
@@ -1996,7 +2028,7 @@
                 }
             }
             IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.LEFT,
                     taskSurface,
@@ -2007,7 +2039,7 @@
                 )
             }
             IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> {
-                handleSnapResizingTask(
+                handleSnapResizingTaskOnDrag(
                     taskInfo,
                     SnapPosition.RIGHT,
                     taskSurface,
@@ -2256,31 +2288,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 {
@@ -2348,7 +2355,7 @@
                 }
             }
 
-        private val mTaskbarDesktopTaskListener: TaskbarDesktopTaskListener =
+        private val taskbarDesktopTaskListener: TaskbarDesktopTaskListener =
                 object : TaskbarDesktopTaskListener {
                     override fun onTaskbarCornerRoundingUpdate(
                         hasTasksRequiringTaskbarRounding: Boolean) {
@@ -2365,6 +2372,27 @@
                     }
                 }
 
+        private val desktopModeEntryExitTransitionListener: DesktopModeEntryExitTransitionListener =
+            object : DesktopModeEntryExitTransitionListener {
+                override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {
+                    ProtoLog.v(
+                        WM_SHELL_DESKTOP_MODE,
+                        "IDesktopModeImpl: onEnterDesktopModeTransitionStarted transitionTime=%s",
+                        transitionDuration
+                    )
+                    remoteListener.call { l -> l.onEnterDesktopModeTransitionStarted(transitionDuration) }
+                }
+
+                override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {
+                    ProtoLog.v(
+                        WM_SHELL_DESKTOP_MODE,
+                        "IDesktopModeImpl: onExitDesktopModeTransitionStarted transitionTime=%s",
+                        transitionDuration
+                    )
+                    remoteListener.call { l -> l.onExitDesktopModeTransitionStarted(transitionDuration) }
+                }
+            }
+
         init {
             remoteListener =
                 SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>(
@@ -2372,13 +2400,16 @@
                     { c ->
                         run {
                             c.taskRepository.addVisibleTasksListener(listener, c.mainExecutor)
-                            c.taskbarDesktopTaskListener = mTaskbarDesktopTaskListener
+                            c.taskbarDesktopTaskListener = taskbarDesktopTaskListener
+                            c.desktopModeEnterExitTransitionListener =
+                                desktopModeEntryExitTransitionListener
                         }
                     },
                     { c ->
                         run {
                             c.taskRepository.removeVisibleTasksListener(listener)
                             c.taskbarDesktopTaskListener = null
+                            c.desktopModeEnterExitTransitionListener = null
                         }
                     }
                 )
@@ -2485,6 +2516,15 @@
         fun onTaskbarCornerRoundingUpdate(hasTasksRequiringTaskbarRounding: Boolean)
     }
 
+    /** Defines interface for entering and exiting desktop windowing mode. */
+    interface DesktopModeEntryExitTransitionListener {
+        /** [transitionDuration] time it takes to run enter desktop mode transition */
+        fun onEnterDesktopModeTransitionStarted(transitionDuration: Int)
+
+        /** [transitionDuration] time it takes to run exit desktop mode transition */
+        fun onExitDesktopModeTransitionStarted(transitionDuration: Int)
+    }
+
     /** The positions on a screen that a task can snap to. */
     enum class SnapPosition {
         RIGHT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index d537da8..b902bb4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -60,8 +60,7 @@
  * entering and exiting freeform.
  */
 public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
-    @VisibleForTesting
-    static final int FULLSCREEN_ANIMATION_DURATION = 336;
+    public static final int FULLSCREEN_ANIMATION_DURATION = 336;
 
     private final Context mContext;
     private final Transitions mTransitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
index c2acb87..6002a4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl
@@ -33,4 +33,10 @@
      * [hasTasksRequiringTaskbarRounding] is true.
      */
     oneway void onTaskbarCornerRoundingUpdate(boolean hasTasksRequiringTaskbarRounding);
+
+    /** Entering desktop mode transition is started, send the signal with transition duration. */
+    oneway void onEnterDesktopModeTransitionStarted(int transitionDuration);
+
+    /** Exiting desktop mode transition is started, send the signal with transition duration. */
+    oneway void onExitDesktopModeTransitionStarted(int transitionDuration);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 5d22c1e..ae9d21f62 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -41,6 +41,9 @@
 import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
 import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -81,6 +84,7 @@
 import com.android.wm.shell.draganddrop.anim.TwoFiftyFiftyTargetAnimator;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.split.SplitScreenConstants;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
 import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
@@ -219,8 +223,10 @@
                         displayRegion.splitHorizontally(startHitRegion, endHitRegion);
                     }
 
-                    mTargets.add(new Target(TYPE_SPLIT_LEFT, startHitRegion, startBounds, -1));
-                    mTargets.add(new Target(TYPE_SPLIT_RIGHT, endHitRegion, endBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_LEFT, startHitRegion, startBounds,
+                            SPLIT_INDEX_0));
+                    mTargets.add(new Target(TYPE_SPLIT_RIGHT, endHitRegion, endBounds,
+                            SPLIT_INDEX_1));
                 } else {
                     // TODO(b/349828130), move this into init function and/or the insets updating
                     //  callback
@@ -287,9 +293,10 @@
                         displayRegion.splitVertically(leftHitRegion, rightHitRegion);
                     }
 
-                    mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, topOrLeftBounds,
+                            SPLIT_INDEX_UNDEFINED));
                     mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, bottomOrRightBounds,
-                            -1));
+                            SPLIT_INDEX_UNDEFINED));
                 } else {
                     final Rect topHitRegion = new Rect();
                     final Rect bottomHitRegion = new Rect();
@@ -308,9 +315,10 @@
                         displayRegion.splitHorizontally(topHitRegion, bottomHitRegion);
                     }
 
-                    mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds, -1));
+                    mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topOrLeftBounds,
+                            SPLIT_INDEX_UNDEFINED));
                     mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomOrRightBounds,
-                            -1));
+                            SPLIT_INDEX_UNDEFINED));
                 }
             }
         } else {
@@ -378,9 +386,9 @@
                 ? mFullscreenStarter
                 : mSplitscreenStarter;
         if (mSession.appData != null) {
-            launchApp(mSession, starter, position, hideTaskToken);
+            launchApp(mSession, starter, position, hideTaskToken, target.index);
         } else {
-            launchIntent(mSession, starter, position, hideTaskToken);
+            launchIntent(mSession, starter, position, hideTaskToken, target.index);
         }
 
         if (enableFlexibleSplit()) {
@@ -392,9 +400,10 @@
      * Launches an app provided by SysUI.
      */
     private void launchApp(DragSession session, Starter starter, @SplitPosition int position,
-            @Nullable WindowContainerToken hideTaskToken) {
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d",
-                position);
+            @Nullable WindowContainerToken hideTaskToken, @SplitIndex int splitIndex) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
+                "Launching app data at position=%d index=%d",
+                position, splitIndex);
         final ClipDescription description = session.getClipDescription();
         final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
         final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
@@ -429,7 +438,7 @@
                 }
             }
             starter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
-                    position, opts, hideTaskToken);
+                    position, opts, hideTaskToken, splitIndex);
         }
     }
 
@@ -437,7 +446,7 @@
      * Launches an intent sender provided by an application.
      */
     private void launchIntent(DragSession session, Starter starter, @SplitPosition int position,
-            @Nullable WindowContainerToken hideTaskToken) {
+            @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d",
                 position);
         final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
@@ -452,7 +461,7 @@
         final Bundle opts = baseActivityOpts.toBundle();
         starter.startIntent(session.launchableIntent,
                 session.launchableIntent.getCreatorUserHandle().getIdentifier(),
-                null /* fillIntent */, position, opts, hideTaskToken);
+                null /* fillIntent */, position, opts, hideTaskToken, index);
     }
 
     @Override
@@ -541,7 +550,7 @@
                 @Nullable Bundle options, UserHandle user);
         void startIntent(PendingIntent intent, int userId, Intent fillInIntent,
                 @SplitPosition int position, @Nullable Bundle options,
-                @Nullable WindowContainerToken hideTaskToken);
+                @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index);
         void enterSplitScreen(int taskId, boolean leftOrTop);
 
         /**
@@ -592,7 +601,7 @@
         @Override
         public void startIntent(PendingIntent intent, int userId, @Nullable Intent fillInIntent,
                 int position, @Nullable Bundle options,
-                @Nullable WindowContainerToken hideTaskToken) {
+                @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
             if (hideTaskToken != null) {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                         "Default starter does not support hide task token");
@@ -641,13 +650,13 @@
         final Rect hitRegion;
         // The approximate visual region for where the task will start
         final Rect drawRegion;
-        int index;
+        @SplitIndex int index;
 
         /**
          * @param index 0-indexed, represents which position of drop target this object represents,
          *              0 to N for left to right, top to bottom
          */
-        public Target(@Type int t, Rect hit, Rect draw, int index) {
+        public Target(@Type int t, Rect hit, Rect draw, @SplitIndex int index) {
             type = t;
             hitRegion = hit;
             drawRegion = draw;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
index 9f532f5..5461952 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/anim/TwoFiftyFiftyTargetAnimator.kt
@@ -22,6 +22,10 @@
 import com.android.wm.shell.R
 import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.draganddrop.SplitDragPolicy.Target
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_2
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_3
 
 /**
  * Represents Drop Zone targets and animations for when the system is currently in a 2 app 50/50
@@ -98,7 +102,7 @@
                     farStartBounds.right + halfDividerWidth,
                     farStartBounds.bottom
                 ),
-                farStartBounds, 0
+                farStartBounds, SPLIT_INDEX_0
             )
         )
         targets.add(
@@ -110,7 +114,7 @@
                     startBounds.right + halfDividerWidth,
                     startBounds.bottom
                 ),
-                startBounds, 1
+                startBounds, SPLIT_INDEX_1
             )
         )
         targets.add(
@@ -120,7 +124,7 @@
                     endBounds.left - halfDividerWidth,
                     endBounds.top, endBounds.right, endBounds.bottom
                 ),
-                endBounds, 2
+                endBounds, SPLIT_INDEX_2
             )
         )
         targets.add(
@@ -130,7 +134,7 @@
                     farEndBounds.left - halfDividerWidth,
                     farEndBounds.top, farEndBounds.right, farEndBounds.bottom
                 ),
-                farEndBounds, 3
+                farEndBounds, SPLIT_INDEX_3
             )
         )
 
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/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 d415c10..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,
@@ -702,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/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 417a655..1c58dbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -1308,6 +1308,9 @@
                 // otherwise a new transition will notify the relevant observers
                 if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
                     mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
+                } else if (!toHome && mState == STATE_NEW_TASK
+                        && allAppsAreTranslucent(mOpeningTasks)) {
+                    // We are opening a translucent app. Launcher is still visible so we do nothing.
                 } else if (!toHome) {
                     // For some transitions, we may have notified home activity that it became
                     // visible. We need to notify the observer that we are no longer going home.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 3e6d36c..39ed9ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -54,10 +54,27 @@
      */
     int STAGE_TYPE_SIDE = 1;
 
+    /**
+     * Position independent stage identifier for a given Stage
+     */
+    int STAGE_TYPE_A = 2;
+    /**
+     * Position independent stage identifier for a given Stage
+     */
+    int STAGE_TYPE_B = 3;
+    /**
+     * Position independent stage identifier for a given Stage
+     */
+    int STAGE_TYPE_C = 4;
+
     @IntDef(prefix = { "STAGE_TYPE_" }, value = {
             STAGE_TYPE_UNDEFINED,
             STAGE_TYPE_MAIN,
-            STAGE_TYPE_SIDE
+            STAGE_TYPE_SIDE,
+            // Used for flexible split
+            STAGE_TYPE_A,
+            STAGE_TYPE_B,
+            STAGE_TYPE_C
     })
     @interface StageType {}
 
@@ -128,6 +145,9 @@
             case STAGE_TYPE_UNDEFINED: return "UNDEFINED";
             case STAGE_TYPE_MAIN: return "MAIN";
             case STAGE_TYPE_SIDE: return "SIDE";
+            case STAGE_TYPE_A: return "STAGE_A";
+            case STAGE_TYPE_B: return "STAGE_B";
+            case STAGE_TYPE_C: return "STAGE_C";
             default: return "UNKNOWN(" + stage + ")";
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 6398d31..4f0f676 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -24,6 +24,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.common.MultiInstanceHelper.getComponent;
 import static com.android.wm.shell.common.MultiInstanceHelper.getShortcutComponent;
 import static com.android.wm.shell.common.MultiInstanceHelper.samePackage;
@@ -33,6 +34,9 @@
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -98,6 +102,7 @@
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.shared.annotations.ExternalThread;
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
 import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
@@ -325,7 +330,6 @@
     /**
      * @return an Array of RunningTaskInfo's ordered by leftToRight or topTopBottom
      */
-    @Nullable
     public ActivityManager.RunningTaskInfo[] getAllTaskInfos() {
         // TODO(b/349828130) Add the third stage task info and not rely on positions
         ActivityManager.RunningTaskInfo topLeftTask = getTaskInfo(SPLIT_POSITION_TOP_OR_LEFT);
@@ -335,7 +339,7 @@
             return new ActivityManager.RunningTaskInfo[]{topLeftTask, bottomRightTask};
         }
 
-        return null;
+        return new ActivityManager.RunningTaskInfo[0];
     }
 
     /** Check task is under split or not by taskId. */
@@ -405,7 +409,7 @@
     public void prepareEnterSplitScreen(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
         mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition,
-                false /* resizeAnim */);
+                false /* resizeAnim */, SPLIT_INDEX_UNDEFINED);
     }
 
     /**
@@ -451,6 +455,24 @@
         }
     }
 
+    /**
+     * Determines which split index a new instance of a task should take.
+     * @param callingTask The task requesting a new instance.
+     * @return the split index of the new instance
+     */
+    @SplitIndex
+    public int determineNewInstanceIndex(@NonNull ActivityManager.RunningTaskInfo callingTask) {
+        if (!enableFlexibleSplit()) {
+            throw new IllegalStateException("Use determineNewInstancePosition");
+        }
+        if (callingTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+                || getSplitPosition(callingTask.taskId) == SPLIT_POSITION_TOP_OR_LEFT) {
+            return SPLIT_INDEX_1;
+        } else {
+            return SPLIT_INDEX_0;
+        }
+    }
+
     public void enterSplitScreen(int taskId, boolean leftOrTop) {
         enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
     }
@@ -685,7 +707,10 @@
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startIntentWithInstanceId: reason=%d",
                 ENTER_REASON_LAUNCHER);
         mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
-        startIntent(intent, userId, fillInIntent, position, options, null /* hideTaskToken */);
+        // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+        //  specific cases in the future. Only focusing on parity with starting intent/task
+        startIntent(intent, userId, fillInIntent, position, options, null /* hideTaskToken */,
+                SPLIT_INDEX_UNDEFINED);
     }
 
     private void startIntentAndTask(PendingIntent pendingIntent, int userId1,
@@ -775,9 +800,9 @@
     @Override
     public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent,
             @SplitPosition int position, @Nullable Bundle options,
-            @Nullable WindowContainerToken hideTaskToken) {
+            @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
         startIntent(intent, userId1, fillInIntent, position, options, hideTaskToken,
-                false /* forceLaunchNewTask */);
+                false /* forceLaunchNewTask */, index);
     }
 
     /**
@@ -790,7 +815,8 @@
      */
     public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent,
             @SplitPosition int position, @Nullable Bundle options,
-            @Nullable WindowContainerToken hideTaskToken, boolean forceLaunchNewTask) {
+            @Nullable WindowContainerToken hideTaskToken, boolean forceLaunchNewTask,
+            @SplitIndex int index) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                 "startIntent(): intent=%s user=%d fillInIntent=%s position=%d", intent, userId1,
                 fillInIntent, position);
@@ -816,7 +842,7 @@
         if (taskInfo != null) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                     "Found suitable background task=%s", taskInfo);
-            mStageCoordinator.startTask(taskInfo.taskId, position, options, hideTaskToken);
+            mStageCoordinator.startTask(taskInfo.taskId, position, options, hideTaskToken, index);
 
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Start task in background");
             return;
@@ -841,7 +867,8 @@
             }
         }
 
-        mStageCoordinator.startIntent(intent, fillInIntent, position, options, hideTaskToken);
+        mStageCoordinator.startIntent(intent, fillInIntent, position, options, hideTaskToken,
+                index);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 84004941..3091be5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
 import static com.android.wm.shell.shared.animation.Interpolators.ALPHA_IN;
@@ -55,6 +56,9 @@
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /** Manages transition animations for split-screen. */
@@ -268,22 +272,21 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback,
-            @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
-            @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+            @NonNull Map<WindowContainerToken, SplitDecorManager> rootDecorMap) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "playResizeAnimation: transition=%d", info.getDebugId());
         initTransition(transition, finishTransaction, finishCallback);
 
+        Set<WindowContainerToken> rootDecorKeys = rootDecorMap.keySet();
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             final TransitionInfo.Change change = info.getChanges().get(i);
-            if (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer())) {
+            if (rootDecorKeys.contains(change.getContainer())) {
                 final SurfaceControl leash = change.getLeash();
                 startTransaction.setPosition(leash, change.getEndAbsBounds().left,
                         change.getEndAbsBounds().top);
                 startTransaction.setWindowCrop(leash, change.getEndAbsBounds().width(),
                         change.getEndAbsBounds().height());
 
-                SplitDecorManager decor = mainRoot.equals(change.getContainer())
-                        ? mainDecor : sideDecor;
+                SplitDecorManager decor = rootDecorMap.get(change.getContainer());
 
                 // This is to ensure onFinished be called after all animations ended.
                 ValueAnimator va = new ValueAnimator();
@@ -433,15 +436,22 @@
             Transitions.TransitionHandler handler,
             @Nullable TransitionConsumedCallback consumedCallback,
             @Nullable TransitionFinishedCallback finishCallback,
-            @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
+            @Nullable SplitDecorManager mainDecor, @Nullable SplitDecorManager sideDecor,
+            @Nullable List<SplitDecorManager> decorManagers) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "  splitTransition deduced Resize split screen.");
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setResizeTransition: hasPendingResize=%b",
                 mPendingResize != null);
         if (mPendingResize != null) {
             mPendingResize.cancel(null);
-            mainDecor.cancelRunningAnimations();
-            sideDecor.cancelRunningAnimations();
+            if (enableFlexibleSplit()) {
+                for (SplitDecorManager stage : decorManagers) {
+                    stage.cancelRunningAnimations();
+                }
+            } else {
+                mainDecor.cancelRunningAnimations();
+                sideDecor.cancelRunningAnimations();
+            }
             mAnimations.clear();
             onFinish(null /* wct */);
         }
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 7d1ffb8..f07ae44 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
@@ -33,6 +33,7 @@
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
 import static com.android.wm.shell.common.split.SplitScreenUtils.isPartiallyOffscreen;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
@@ -43,6 +44,7 @@
 import static com.android.wm.shell.shared.TransitionUtil.isOrderOnly;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
@@ -51,11 +53,13 @@
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.splitPositionToString;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_A;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_B;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
 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.SplitScreen.stageTypeToString;
 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;
@@ -143,6 +147,7 @@
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.shared.split.SplitBounds;
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
 import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
@@ -154,11 +159,15 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * Coordinates the staging (visibility, sizing, ...) of the split-screen stages.
@@ -179,10 +188,11 @@
     // entered
     private static final int DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS = 1000;
 
-    private final StageTaskListener mMainStage;
-    private final StageTaskListener mSideStage;
+    private StageTaskListener mMainStage;
+    private StageTaskListener mSideStage;
     @SplitPosition
     private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
+    private StageOrderOperator mStageOrderOperator;
 
     private final int mDisplayId;
     private SplitLayout mSplitLayout;
@@ -336,22 +346,32 @@
         taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
 
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Creating main/side root task");
-        mMainStage = new StageTaskListener(
-                mContext,
-                mTaskOrganizer,
-                mDisplayId,
-                this /*stageListenerCallbacks*/,
-                mSyncQueue,
-                iconProvider,
-                mWindowDecorViewModel);
-        mSideStage = new StageTaskListener(
-                mContext,
-                mTaskOrganizer,
-                mDisplayId,
-                this /*stageListenerCallbacks*/,
-                mSyncQueue,
-                iconProvider,
-                mWindowDecorViewModel);
+        if (enableFlexibleSplit()) {
+            mStageOrderOperator = new StageOrderOperator(mContext,
+                    mTaskOrganizer,
+                    mDisplayId,
+                    this /*stageListenerCallbacks*/,
+                    mSyncQueue,
+                    iconProvider,
+                    mWindowDecorViewModel);
+        } else {
+            mMainStage = new StageTaskListener(
+                    mContext,
+                    mTaskOrganizer,
+                    mDisplayId,
+                    this /*stageListenerCallbacks*/,
+                    mSyncQueue,
+                    iconProvider,
+                    mWindowDecorViewModel, STAGE_TYPE_MAIN);
+            mSideStage = new StageTaskListener(
+                    mContext,
+                    mTaskOrganizer,
+                    mDisplayId,
+                    this /*stageListenerCallbacks*/,
+                    mSyncQueue,
+                    iconProvider,
+                    mWindowDecorViewModel, STAGE_TYPE_SIDE);
+        }
         mDisplayController = displayController;
         mDisplayImeController = displayImeController;
         mDisplayInsetsController = displayInsetsController;
@@ -423,24 +443,63 @@
     }
 
     public boolean isSplitScreenVisible() {
-        return mSideStage.mVisible && mMainStage.mVisible;
+        if (enableFlexibleSplit()) {
+            return runForActiveStagesAllMatch((stage) -> stage.mVisible);
+        } else {
+            return mSideStage.mVisible && mMainStage.mVisible;
+        }
     }
 
-    private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask) {
-        mMainStage.activate(wct, includingTopTask);
+    /**
+     * @param includingTopTask reparents the current top task into the stage defined by index
+     *                         (or mainStage in legacy split)
+     * @param index the index to move the current visible task into, if undefined will arbitrarily
+     *              choose a stage to launch into
+     */
+    private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask,
+            int index) {
+        if (enableFlexibleSplit()) {
+            mStageOrderOperator.onEnteringSplit(SNAP_TO_2_50_50);
+            if (index == SPLIT_INDEX_UNDEFINED || !includingTopTask) {
+                // If we aren't includingTopTask, then the call to activate on the stage is
+                // effectively a no-op. Previously the stage kept track of the "isActive" state,
+                // but now that gets set in the "onEnteringSplit" call above.
+                //
+                // index == UNDEFINED case might change, but as of now no use case where we activate
+                // without an index specified.
+                return;
+            }
+            @SplitIndex int oppositeIndex = index == SPLIT_INDEX_0 ? SPLIT_INDEX_1 : SPLIT_INDEX_0;
+            StageTaskListener activatingStage = mStageOrderOperator.getStageForIndex(oppositeIndex);
+            activatingStage.activate(wct, includingTopTask);
+        } else {
+            mMainStage.activate(wct, includingTopTask);
+        }
     }
 
     public boolean isSplitActive() {
-        return mMainStage.isActive();
+        if (enableFlexibleSplit()) {
+            return mStageOrderOperator.isActive();
+        } else {
+            return mMainStage.isActive();
+        }
     }
 
     /**
      * Deactivates main stage by removing the stage from the top level split root (usually when a
      * task underneath gets removed from the stage root).
-     * @param reparentToTop whether we want to put the stage root back on top
+     * @param stageToTop stage which we want to put on top
      */
-    private void deactivateSplit(WindowContainerTransaction wct, boolean reparentToTop) {
-        mMainStage.deactivate(wct, reparentToTop);
+    private void deactivateSplit(WindowContainerTransaction wct, @StageType int stageToTop) {
+        if (enableFlexibleSplit()) {
+            StageTaskListener stageToDeactivate = mStageOrderOperator.getAllStages().stream()
+                    .filter(stage -> stage.getId() == stageToTop)
+                    .findFirst().orElseThrow();
+            stageToDeactivate.deactivate(wct, true /*toTop*/);
+            mStageOrderOperator.onExitingSplit();
+        } else {
+            mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
+        }
     }
 
     /** @return whether this transition-request has the launch-adjacent flag. */
@@ -464,11 +523,12 @@
         // If one of the splitting tasks support auto-pip, wm-core might reparent the task to TDA
         // and file a TRANSIT_PIP transition when finishing transitions.
         // @see com.android.server.wm.RootWindowContainer#moveActivityToPinnedRootTask
-        if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
-            return true;
+        if (enableFlexibleSplit()) {
+            return mStageOrderOperator.getActiveStages().stream()
+                    .anyMatch(stage -> stage.getChildCount() == 0);
+        } else {
+            return mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0;
         }
-
-        return false;
     }
 
     /** Checks if `transition` is a pending enter-split transition. */
@@ -478,10 +538,19 @@
 
     @StageType
     int getStageOfTask(int taskId) {
-        if (mMainStage.containsTask(taskId)) {
-            return STAGE_TYPE_MAIN;
-        } else if (mSideStage.containsTask(taskId)) {
-            return STAGE_TYPE_SIDE;
+        if (enableFlexibleSplit()) {
+            StageTaskListener stageTaskListener = mStageOrderOperator.getActiveStages().stream()
+                    .filter(stage -> stage.containsTask(taskId))
+                    .findFirst().orElse(null);
+            if (stageTaskListener != null) {
+                return stageTaskListener.getId();
+            }
+        } else {
+            if (mMainStage.containsTask(taskId)) {
+                return STAGE_TYPE_MAIN;
+            } else if (mSideStage.containsTask(taskId)) {
+                return STAGE_TYPE_SIDE;
+            }
         }
 
         return STAGE_TYPE_UNDEFINED;
@@ -491,14 +560,22 @@
         if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskId) {
             return true;
         }
-        return mMainStage.isRootTaskId(taskId) || mSideStage.isRootTaskId(taskId);
+        if (enableFlexibleSplit()) {
+            return mStageOrderOperator.getActiveStages().stream()
+                    .anyMatch((stage) -> stage.isRootTaskId(taskId));
+        } else {
+            return mMainStage.isRootTaskId(taskId) || mSideStage.isRootTaskId(taskId);
+        }
     }
 
     boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitPosition int stagePosition,
             WindowContainerTransaction wct) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "moveToStage: task=%d position=%d", task.taskId,
                 stagePosition);
-        prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */);
+        // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+        //  specific cases in the future. Only focusing on parity with starting intent/task
+        prepareEnterSplitScreen(wct, task, stagePosition, false /* resizeAnim */,
+                SPLIT_INDEX_UNDEFINED);
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct,
                 null, this,
                 isSplitScreenVisible()
@@ -596,11 +673,14 @@
      *                      same window container transaction as the starting of the intent.
      */
     void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options,
-            @Nullable WindowContainerToken hideTaskToken) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startTask: task=%d position=%d", taskId, position);
+            @Nullable WindowContainerToken hideTaskToken, @SplitIndex int index) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startTask: task=%d position=%d index=%d",
+                taskId, position, index);
         mSplitRequest = new SplitRequest(taskId, position);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
+        options = enableFlexibleSplit()
+                ? resolveStartStageForIndex(options, null /*wct*/, index)
+                : resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
         if (hideTaskToken != null) {
             ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Reordering hide-task to bottom");
             wct.reorder(hideTaskToken, false /* onTop */);
@@ -624,7 +704,7 @@
         // If split screen is not activated, we're expecting to open a pair of apps to split.
         final int extraTransitType = isSplitActive()
                 ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
-        prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
+        prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
                 extraTransitType, !mIsDropEntering);
@@ -636,13 +716,16 @@
      *                      same window container transaction as the starting of the intent.
      */
     void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
-            @Nullable Bundle options, @Nullable WindowContainerToken hideTaskToken) {
+            @Nullable Bundle options, @Nullable WindowContainerToken hideTaskToken,
+            @SplitIndex int index) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startIntent: intent=%s position=%d", intent.getIntent(),
                 position);
         mSplitRequest = new SplitRequest(intent.getIntent(), position);
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
+        options = enableFlexibleSplit()
+                ? resolveStartStageForIndex(options, null /*wct*/, index)
+                : resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
         if (hideTaskToken != null) {
             ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Reordering hide-task to bottom");
             wct.reorder(hideTaskToken, false /* onTop */);
@@ -667,13 +750,17 @@
         // If split screen is not activated, we're expecting to open a pair of apps to split.
         final int extraTransitType = isSplitActive()
                 ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
-        prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
+        prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
                 extraTransitType, !mIsDropEntering);
     }
 
-    /** Starts 2 tasks in one transition. */
+    /**
+     * Starts 2 tasks in one transition.
+     * @param taskId1 starts in the mSideStage
+     * @param taskId2 starts in the mainStage #startWithTask()
+     */
     void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, @Nullable Bundle options2,
             @SplitPosition int splitPosition, @PersistentSnapPosition int snapPosition,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
@@ -688,11 +775,19 @@
 
         setSideStagePosition(splitPosition, wct);
         options1 = options1 != null ? options1 : new Bundle();
-        addActivityOptions(options1, mSideStage);
+        StageTaskListener stageForTask1;
+        if (enableFlexibleSplit()) {
+            stageForTask1 = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+                    true /*checkAllStagesIfNotActive*/);
+        } else {
+            stageForTask1 = mSideStage;
+        }
+        addActivityOptions(options1, stageForTask1);
         prepareTasksForSplitScreen(new int[] {taskId1, taskId2}, wct);
         wct.startTask(taskId1, options1);
 
-        startWithTask(wct, taskId2, options2, snapPosition, remoteTransition, instanceId);
+        startWithTask(wct, taskId2, options2, snapPosition, remoteTransition, instanceId,
+                splitPosition);
     }
 
     /** Start an intent and a task to a split pair in one transition. */
@@ -722,7 +817,8 @@
         wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
         prepareTasksForSplitScreen(new int[] {taskId}, wct);
 
-        startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
+        startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId,
+                splitPosition);
     }
 
     /**
@@ -766,7 +862,8 @@
         wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
         prepareTasksForSplitScreen(new int[] {taskId}, wct);
 
-        startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
+        startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId,
+                splitPosition);
     }
 
     /**
@@ -796,11 +893,14 @@
      */
     private void startWithTask(WindowContainerTransaction wct, int mainTaskId,
             @Nullable Bundle mainOptions, @PersistentSnapPosition int snapPosition,
-            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+            @Nullable RemoteTransition remoteTransition, InstanceId instanceId,
+            @SplitPosition int splitPosition) {
         if (!isSplitActive()) {
             // Build a request WCT that will launch both apps such that task 0 is on the main stage
             // while task 1 is on the side stage.
-            activateSplit(wct, false /* reparentToTop */);
+            // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+            //  specific cases in the future. Only focusing on parity with starting intent/task
+            activateSplit(wct, false /* reparentToTop */, SPLIT_INDEX_UNDEFINED);
         }
         mSplitLayout.setDivideRatio(snapPosition);
         updateWindowBounds(mSplitLayout, wct);
@@ -808,10 +908,19 @@
         wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
                 false /* reparentLeafTaskIfRelaunch */);
         setRootForceTranslucent(false, wct);
-
+        // All callers of this method set the correct activity options on mSideStage,
+        // so we choose the opposite stage for this method
+        StageTaskListener stage;
+        if (enableFlexibleSplit()) {
+            stage = mStageOrderOperator
+                    .getStageForLegacyPosition(reverseSplitPosition(splitPosition),
+                            false /*checkAllStagesIfNotActive*/);
+        } else {
+            stage = mMainStage;
+        }
         // Make sure the launch options will put tasks in the corresponding split roots
         mainOptions = mainOptions != null ? mainOptions : new Bundle();
-        addActivityOptions(mainOptions, mMainStage);
+        addActivityOptions(mainOptions, stage);
 
         // Add task launch requests
         wct.startTask(mainTaskId, mainOptions);
@@ -867,7 +976,9 @@
         if (!isSplitActive()) {
             // Build a request WCT that will launch both apps such that task 0 is on the main stage
             // while task 1 is on the side stage.
-            activateSplit(wct, false /* reparentToTop */);
+            // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+            //  specific cases in the future. Only focusing on parity with starting intent/task
+            activateSplit(wct, false /* reparentToTop */, SPLIT_INDEX_UNDEFINED);
         }
 
         setSideStagePosition(splitPosition, wct);
@@ -975,6 +1086,31 @@
         mSideStage.evictInvisibleChildren(wct);
     }
 
+    /**
+     * @param index for the new stage that will be opening. Ex. if app is dragged to
+     *              index=1, then this will tell the stage at index=1 to launch the task
+     *              in the wct in that stage. This doesn't verify that the non-specified
+     *              indices' stages have their tasks correctly set/re-parented.
+     */
+    Bundle resolveStartStageForIndex(@Nullable Bundle options,
+            @Nullable WindowContainerTransaction wct,
+            @SplitIndex int index) {
+        StageTaskListener oppositeStage;
+        if (index == SPLIT_INDEX_UNDEFINED) {
+            // Arbitrarily choose a stage
+            oppositeStage = mStageOrderOperator.getStageForIndex(SPLIT_INDEX_1);
+        } else {
+            oppositeStage = mStageOrderOperator.getStageForIndex(index);
+        }
+        if (options == null) {
+            options = new Bundle();
+        }
+        updateStageWindowBoundsForIndex(wct, index);
+        addActivityOptions(options, oppositeStage);
+
+        return options;
+    }
+
     Bundle resolveStartStage(@StageType int stage, @SplitPosition int position,
             @Nullable Bundle options, @Nullable WindowContainerTransaction wct) {
         switch (stage) {
@@ -1042,20 +1178,35 @@
             return INVALID_TASK_ID;
         }
 
-        return mSideStagePosition == splitPosition
-                ? mSideStage.getTopVisibleChildTaskId()
-                : mMainStage.getTopVisibleChildTaskId();
+        if (enableFlexibleSplit()) {
+            StageTaskListener stage = mStageOrderOperator.getStageForLegacyPosition(splitPosition,
+                    true /*checkAllStagesIfNotActive*/);
+            return stage != null ? stage.getTopVisibleChildTaskId() : INVALID_TASK_ID;
+        } else {
+            return mSideStagePosition == splitPosition
+                    ? mSideStage.getTopVisibleChildTaskId()
+                    : mMainStage.getTopVisibleChildTaskId();
+        }
     }
 
     void switchSplitPosition(String reason) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "switchSplitPosition");
         final SurfaceControl.Transaction t = mTransactionPool.acquire();
         mTempRect1.setEmpty();
-        final StageTaskListener topLeftStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
-        final StageTaskListener bottomRightStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
-
+        final StageTaskListener topLeftStage;
+        final StageTaskListener bottomRightStage;
+        if (enableFlexibleSplit()) {
+            topLeftStage = mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+                            false /*checkAllStagesIfNotActive*/);
+            bottomRightStage = mStageOrderOperator
+                    .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                    false /*checkAllStagesIfNotActive*/);
+        } else {
+            topLeftStage =
+                    mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+            bottomRightStage =
+                    mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+        }
         // Don't allow windows or divider to be focused during animation (mRootTaskInfo is the
         // parent of all 3 leaves). We don't want the user to be able to tap and focus a window
         // while it is moving across the screen, because granting focus also recalculates the
@@ -1092,23 +1243,40 @@
                 });
 
         ProtoLog.v(WM_SHELL_SPLIT_SCREEN, "Switch split position: %s", reason);
-        mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
-                getSideStagePosition(), mSideStage.getTopChildTaskUid(),
-                mSplitLayout.isLeftRightSplit());
+        if (enableFlexibleSplit()) {
+            // TODO(b/374825718) update logging for 2+ apps
+        } else {
+            mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                    getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                    mSplitLayout.isLeftRightSplit());
+        }
     }
 
     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();
+        StageTaskListener stage = enableFlexibleSplit()
+                ? mStageOrderOperator.getStageForLegacyPosition(mSideStagePosition,
+                true /*checkAllStagesIfNotActive*/)
+                : mSideStage;
 
-        if (mSideStage.mVisible && updateBounds) {
+        if (stage.mVisible) {
+            if (wct == null) {
+                // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
+                onLayoutSizeChanged(mSplitLayout);
+            } else {
+                updateWindowBounds(mSplitLayout, wct);
+                sendOnBoundsChanged();
+            }
+        }
+    }
+
+    private void updateStageWindowBoundsForIndex(@Nullable WindowContainerTransaction wct,
+            @SplitIndex int index) {
+        StageTaskListener stage = mStageOrderOperator.getStageForIndex(index);
+        if (stage.mVisible) {
             if (wct == null) {
                 // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
                 onLayoutSizeChanged(mSplitLayout);
@@ -1158,10 +1326,17 @@
     void recordLastActiveStage() {
         if (!isSplitActive() || !isSplitScreenVisible()) {
             mLastActiveStage = STAGE_TYPE_UNDEFINED;
-        } else if (mMainStage.isFocused()) {
-            mLastActiveStage = STAGE_TYPE_MAIN;
-        } else if (mSideStage.isFocused()) {
-            mLastActiveStage = STAGE_TYPE_SIDE;
+        } else if (enableFlexibleSplit()) {
+            mStageOrderOperator.getActiveStages().stream()
+                    .filter(StageTaskListener::isFocused)
+                    .findFirst()
+                    .ifPresent(stage -> mLastActiveStage = stage.getId());
+        } else {
+            if (mMainStage.isFocused()) {
+                mLastActiveStage = STAGE_TYPE_MAIN;
+            } else if (mSideStage.isFocused()) {
+                mLastActiveStage = STAGE_TYPE_SIDE;
+            }
         }
     }
 
@@ -1218,7 +1393,7 @@
         mSplitLayout.getInvisibleBounds(mTempRect1);
         if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
             mSideStage.removeAllTasks(wct, false /* toTop */);
-            deactivateSplit(wct, false /* reparentToTop */);
+            deactivateSplit(wct, STAGE_TYPE_UNDEFINED);
             wct.reorder(mRootTaskInfo.token, false /* onTop */);
             setRootForceTranslucent(true, wct);
             wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
@@ -1247,7 +1422,7 @@
                 childrenToTop.fadeOutDecor(() -> {
                     WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
                     mIsExiting = false;
-                    deactivateSplit(finishedWCT, childrenToTop == mMainStage /* reparentToTop */);
+                    deactivateSplit(finishedWCT, childrenToTop.getId());
                     mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */);
                     finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
                     setRootForceTranslucent(true, finishedWCT);
@@ -1275,6 +1450,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);
     }
 
@@ -1373,8 +1550,13 @@
         mRecentTasks.ifPresent(recentTasks -> {
             // Notify recents if we are exiting in a way that breaks the pair, and disable further
             // updates to splits in the recents until we enter split again
-            mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
-            mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+            if (enableFlexibleSplit()) {
+                runForActiveStages((stage) ->
+                        stage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId)));
+            } else {
+                mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+                mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+            }
         });
         logExit(exitReason);
     }
@@ -1387,15 +1569,22 @@
     void prepareExitSplitScreen(@StageType int stageToTop,
             @NonNull WindowContainerTransaction wct) {
         if (!isSplitActive()) return;
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%d", stageToTop);
-        mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
-        deactivateSplit(wct, stageToTop == STAGE_TYPE_MAIN);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%s",
+                stageTypeToString(stageToTop));
+        if (enableFlexibleSplit()) {
+            mStageOrderOperator.getActiveStages().stream()
+                    .filter(stage -> stage.getId() != stageToTop)
+                    .forEach(stage -> stage.removeAllTasks(wct, false /*toTop*/));
+        } else {
+            mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
+        }
+        deactivateSplit(wct, stageToTop);
     }
 
     private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen");
         prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED,
-                !mIsDropEntering);
+                !mIsDropEntering, SPLIT_INDEX_UNDEFINED);
     }
 
     /**
@@ -1404,7 +1593,7 @@
      */
     void prepareEnterSplitScreen(WindowContainerTransaction wct,
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
-            boolean resizeAnim) {
+            boolean resizeAnim, @SplitIndex int index) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareEnterSplitScreen: position=%d resize=%b",
                 startPosition, resizeAnim);
         onSplitScreenEnter();
@@ -1416,7 +1605,7 @@
         if (isSplitActive()) {
             prepareBringSplit(wct, taskInfo, startPosition, resizeAnim);
         } else {
-            prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim);
+            prepareActiveSplit(wct, taskInfo, startPosition, resizeAnim, index);
         }
     }
 
@@ -1437,14 +1626,22 @@
             if (!mSkipEvictingMainStageChildren) {
                 mMainStage.evictAllChildren(wct);
             }
-            mMainStage.reparentTopTask(wct);
+            // TODO(b/349828130) revisit bring split from BG to FG scenarios
+            if (enableFlexibleSplit()) {
+                runForActiveStages(stage -> stage.reparentTopTask(wct));
+            } else {
+                mMainStage.reparentTopTask(wct);
+            }
             prepareSplitLayout(wct, resizeAnim);
         }
     }
 
+    /**
+     * @param index The index that has already been assigned a stage
+     */
     private void prepareActiveSplit(WindowContainerTransaction wct,
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition,
-            boolean resizeAnim) {
+            boolean resizeAnim, @SplitIndex int index) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareActiveSplit: task=%d isSplitVisible=%b",
                 taskInfo != null ? taskInfo.taskId : -1, isSplitScreenVisible());
         // We handle split visibility itself on shell transition, but sometimes we didn't
@@ -1454,7 +1651,7 @@
             setSideStagePosition(startPosition, wct);
             mSideStage.addTask(taskInfo, wct);
         }
-        activateSplit(wct, true /* reparentToTop */);
+        activateSplit(wct, true /* reparentToTop */, index);
         prepareSplitLayout(wct, resizeAnim);
     }
 
@@ -1481,8 +1678,13 @@
     void finishEnterSplitScreen(SurfaceControl.Transaction finishT) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "finishEnterSplitScreen");
         mSplitLayout.update(null, true /* resetImePosition */);
-        mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash);
-        mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash);
+        if (enableFlexibleSplit()) {
+            runForActiveStages((stage) ->
+                    stage.getSplitDecorManager().inflate(mContext, stage.mRootLeash));
+        } else {
+            mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash);
+            mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash);
+        }
         setDividerVisibility(true, finishT);
         // Ensure divider surface are re-parented back into the hierarchy at the end of the
         // transition. See Transition#buildFinishTransaction for more detail.
@@ -1496,6 +1698,10 @@
         mSplitRequest = null;
         updateRecentTasksSplitPair();
 
+        if (enableFlexibleSplit()) {
+            // TODO(b/374825718) log 2+ apps
+            return;
+        }
         mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
                 getMainStagePosition(), mMainStage.getTopChildTaskUid(),
                 getSideStagePosition(), mSideStage.getTopChildTaskUid(),
@@ -1507,6 +1713,15 @@
         outBottomOrRightBounds.set(mSplitLayout.getBounds2());
     }
 
+    private void runForActiveStages(Consumer<StageTaskListener> consumer) {
+        mStageOrderOperator.getActiveStages().forEach(consumer);
+    }
+
+    private boolean runForActiveStagesAllMatch(Predicate<StageTaskListener> predicate) {
+        List<StageTaskListener> activeStages = mStageOrderOperator.getActiveStages();
+        return !activeStages.isEmpty() && activeStages.stream().allMatch(predicate);
+    }
+
     @SplitPosition
     int getSplitPosition(int taskId) {
         if (mSideStage.getTopVisibleChildTaskId() == taskId) {
@@ -1520,6 +1735,9 @@
     private void addActivityOptions(Bundle opts, @Nullable StageTaskListener launchTarget) {
         ActivityOptions options = ActivityOptions.fromBundle(opts);
         if (launchTarget != null) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                    "addActivityOptions setting launch root for stage=%s",
+                    stageTypeToString(launchTarget.getId()));
             options.setLaunchRootTask(launchTarget.mRootTaskInfo.token);
         }
         // Put BAL flags to avoid activity start aborted. Otherwise, flows like shortcut to split
@@ -1563,8 +1781,15 @@
             listener.onSplitBoundsChanged(mSplitLayout.getRootBounds(), getMainStageBounds(),
                     getSideStageBounds());
         }
-        mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
-        mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+        if (enableFlexibleSplit()) {
+            // TODO(b/349828130) replace w/ stageID
+            mStageOrderOperator.getAllStages().forEach(
+                    stage -> stage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_UNDEFINED)
+            );
+        } else {
+            mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE);
+            mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN);
+        }
     }
 
     private void sendOnStagePositionChanged() {
@@ -1588,20 +1813,35 @@
             boolean present, boolean visible) {
         int stage;
         if (present) {
-            stage = stageListener == mSideStage ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+            if (enableFlexibleSplit()) {
+                stage = stageListener.getId();
+            } else {
+                stage = stageListener == mSideStage ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+            }
         } else {
             // No longer on any stage
             stage = STAGE_TYPE_UNDEFINED;
         }
-        if (stage == STAGE_TYPE_MAIN) {
-            mLogger.logMainStageAppChange(getMainStagePosition(), mMainStage.getTopChildTaskUid(),
-                    mSplitLayout.isLeftRightSplit());
-        } else if (stage == STAGE_TYPE_SIDE) {
-            mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
-                    mSplitLayout.isLeftRightSplit());
+        if (!enableFlexibleSplit()) {
+            if (stage == STAGE_TYPE_MAIN) {
+                mLogger.logMainStageAppChange(getMainStagePosition(),
+                        mMainStage.getTopChildTaskUid(),
+                        mSplitLayout.isLeftRightSplit());
+            } else if (stage == STAGE_TYPE_SIDE) {
+                mLogger.logSideStageAppChange(getSideStagePosition(),
+                        mSideStage.getTopChildTaskUid(),
+                        mSplitLayout.isLeftRightSplit());
+            }
         }
         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) {
@@ -1619,17 +1859,35 @@
         mRecentTasks.ifPresent(recentTasks -> {
             Rect topLeftBounds = mSplitLayout.getBounds1();
             Rect bottomRightBounds = mSplitLayout.getBounds2();
-            int mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId();
-            int sideStageTopTaskId = mSideStage.getTopVisibleChildTaskId();
+            int sideStageTopTaskId;
+            int mainStageTopTaskId;
+            if (enableFlexibleSplit()) {
+                List<StageTaskListener> activeStages = mStageOrderOperator.getActiveStages();
+                if (activeStages.size() != 2) {
+                    sideStageTopTaskId = mainStageTopTaskId = INVALID_TASK_ID;
+                } else {
+                    // doesn't matter which one we assign to? What matters is the order of 0 and 1?
+                    mainStageTopTaskId = activeStages.get(0).getTopVisibleChildTaskId();
+                    sideStageTopTaskId = activeStages.get(1).getTopVisibleChildTaskId();
+                }
+            } else {
+                mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId();
+                sideStageTopTaskId= mSideStage.getTopVisibleChildTaskId();
+            }
             boolean sideStageTopLeft = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
             int leftTopTaskId;
             int rightBottomTaskId;
-            if (sideStageTopLeft) {
-                leftTopTaskId = sideStageTopTaskId;
-                rightBottomTaskId = mainStageTopTaskId;
-            } else {
+            if (enableFlexibleSplit()) {
                 leftTopTaskId = mainStageTopTaskId;
                 rightBottomTaskId = sideStageTopTaskId;
+            } else {
+                if (sideStageTopLeft) {
+                    leftTopTaskId = sideStageTopTaskId;
+                    rightBottomTaskId = mainStageTopTaskId;
+                } else {
+                    leftTopTaskId = mainStageTopTaskId;
+                    rightBottomTaskId = sideStageTopTaskId;
+                }
             }
 
             if (Flags.enableFlexibleTwoAppSplit()) {
@@ -1738,29 +1996,59 @@
     @VisibleForTesting
     @Override
     public void onRootTaskAppeared() {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
-                mRootTaskInfo, mMainStage.mHasRootTask, mSideStage.mHasRootTask);
+        if (enableFlexibleSplit()) {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onRootTaskAppeared: rootTask=%s",
+                mRootTaskInfo);
+            mStageOrderOperator.getAllStages().forEach(stage -> {
+                ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                        "    onRootStageAppeared stageId=%s hasRoot=%b",
+                        stageTypeToString(stage.getId()), stage.mHasRootTask);
+            });
+        } else {
+            ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+                    "onRootTaskAppeared: rootTask=%s mainRoot=%b sideRoot=%b",
+                    mRootTaskInfo, mMainStage.mHasRootTask, mSideStage.mHasRootTask);
+        }
+        boolean notAllStagesHaveRootTask;
+        if (enableFlexibleSplit()) {
+            notAllStagesHaveRootTask = mStageOrderOperator.getAllStages().stream()
+                    .anyMatch((stage) -> !stage.mHasRootTask);
+        } else {
+            notAllStagesHaveRootTask = !mMainStage.mHasRootTask
+                    || !mSideStage.mHasRootTask;
+        }
         // Wait unit all root tasks appeared.
-        if (mRootTaskInfo == null
-                || !mMainStage.mHasRootTask
-                || !mSideStage.mHasRootTask) {
+        if (mRootTaskInfo == null || notAllStagesHaveRootTask) {
             return;
         }
 
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
-        wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+        if (enableFlexibleSplit()) {
+            mStageOrderOperator.getAllStages().forEach(stage ->
+                    wct.reparent(stage.mRootTaskInfo.token, mRootTaskInfo.token, true));
+        } else {
+            wct.reparent(mMainStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+            wct.reparent(mSideStage.mRootTaskInfo.token, mRootTaskInfo.token, true);
+        }
 
-        // Make the stages adjacent to each other so they occlude what's behind them.
-        wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
         setRootForceTranslucent(true, wct);
-        mSplitLayout.getInvisibleBounds(mTempRect1);
-        wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+        if (!enableFlexibleSplit()) {
+            //TODO(b/373709676) Need to figure out how adjacentRoots work for flex split
+
+            // Make the stages adjacent to each other so they occlude what's behind them.
+            wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
+            mSplitLayout.getInvisibleBounds(mTempRect1);
+            wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+        }
         mSyncQueue.queue(wct);
-        mSyncQueue.runInSync(t -> {
-            t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
-        });
-        mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
+        if (!enableFlexibleSplit()) {
+            mSyncQueue.runInSync(t -> {
+                t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
+            });
+            mLaunchAdjacentController.setLaunchAdjacentRoot(mSideStage.mRootTaskInfo.token);
+        } else {
+            // TODO(b/373709676) Need to figure out how adjacentRoots work for flex split
+        }
     }
 
     @Override
@@ -1955,15 +2243,21 @@
     }
 
     @Override
-    public void onSnappedToDismiss(boolean bottomOrRight, @ExitReason int exitReason) {
+    public void onSnappedToDismiss(boolean closedBottomRightStage, @ExitReason int exitReason) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onSnappedToDismiss: bottomOrRight=%b reason=%s",
-                bottomOrRight, exitReasonToString(exitReason));
-        final boolean mainStageToTop =
-                bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
+                closedBottomRightStage, exitReasonToString(exitReason));
+        boolean mainStageToTop =
+                closedBottomRightStage ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
                         : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
-        final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
-
-        final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+        StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
+        int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+        if (enableFlexibleSplit()) {
+            toTopStage = mStageOrderOperator.getStageForLegacyPosition(closedBottomRightStage
+                            ? SPLIT_POSITION_TOP_OR_LEFT
+                            : SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                    false /*checkAllStagesIfNotActive*/);
+            dismissTop = toTopStage.getId();
+        }
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         toTopStage.resetBounds(wct);
         prepareExitSplitScreen(dismissTop, wct);
@@ -1995,8 +2289,21 @@
         updateSurfaceBounds(layout, t, shouldUseParallaxEffect);
         getMainStageBounds(mTempRect1);
         getSideStageBounds(mTempRect2);
-        mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
-        mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+        if (enableFlexibleSplit()) {
+            StageTaskListener ltStage =
+                    mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+                    false /*checkAllStagesIfNotActive*/);
+            StageTaskListener brStage =
+                    mStageOrderOperator.getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                            false /*checkAllStagesIfNotActive*/);
+            ltStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
+            brStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+        } else {
+            mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY,
+                    mShowDecorImmediately);
+            mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY,
+                    mShowDecorImmediately);
+        }
         t.apply();
         mTransactionPool.release(t);
     }
@@ -2012,19 +2319,33 @@
         if (!sizeChanged) {
             // We still need to resize on decor for ensure all current status clear.
             final SurfaceControl.Transaction t = mTransactionPool.acquire();
-            mMainStage.onResized(t);
-            mSideStage.onResized(t);
+            if (enableFlexibleSplit()) {
+                runForActiveStages(stage -> stage.onResized(t));
+            } else {
+                mMainStage.onResized(t);
+                mSideStage.onResized(t);
+            }
             mTransactionPool.release(t);
             return;
         }
-
+        List<SplitDecorManager> decorManagers = new ArrayList<>();
+        SplitDecorManager mainDecor = null;
+        SplitDecorManager sideDecor = null;
+        if (enableFlexibleSplit()) {
+            decorManagers = mStageOrderOperator.getActiveStages().stream()
+                    .map(StageTaskListener::getSplitDecorManager)
+                    .toList();
+        } else {
+            mainDecor = mMainStage.getSplitDecorManager();
+            sideDecor = mSideStage.getSplitDecorManager();
+        }
         sendOnBoundsChanged();
         mSplitLayout.setDividerInteractive(false, false, "onSplitResizeStart");
         mSplitTransitions.startResizeTransition(wct, this, (aborted) -> {
             mSplitLayout.setDividerInteractive(true, false, "onSplitResizeConsumed");
         }, (finishWct, t) -> {
             mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish");
-        }, mMainStage.getSplitDecorManager(), mSideStage.getSplitDecorManager());
+        }, mainDecor, sideDecor, decorManagers);
 
         if (Flags.enableFlexibleTwoAppSplit()) {
             switch (layout.calculateCurrentSnapPosition()) {
@@ -2051,10 +2372,23 @@
      * @return true if stage bounds actually .
      */
     private boolean updateWindowBounds(SplitLayout layout, WindowContainerTransaction wct) {
-        final StageTaskListener topLeftStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
-        final StageTaskListener bottomRightStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+        final StageTaskListener topLeftStage;
+        final StageTaskListener bottomRightStage;
+        if (enableFlexibleSplit()) {
+            topLeftStage = mStageOrderOperator
+                    .getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+                            true /*checkAllStagesIfNotActive*/);
+            bottomRightStage = mStageOrderOperator
+                    .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                            true /*checkAllStagesIfNotActive*/);
+        } else {
+            topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+                    ? mSideStage
+                    : mMainStage;
+            bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+                    ? mMainStage
+                    : mSideStage;
+        }
         boolean updated = layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo,
                 bottomRightStage.mRootTaskInfo);
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateWindowBounds: topLeftStage=%s bottomRightStage=%s",
@@ -2064,10 +2398,23 @@
 
     void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t,
             boolean applyResizingOffset) {
-        final StageTaskListener topLeftStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
-        final StageTaskListener bottomRightStage =
-                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+        final StageTaskListener topLeftStage;
+        final StageTaskListener bottomRightStage;
+        if (enableFlexibleSplit()) {
+            topLeftStage = mStageOrderOperator
+                    .getStageForLegacyPosition(SPLIT_POSITION_TOP_OR_LEFT,
+                            true /*checkAllStagesIfNotActive*/);
+            bottomRightStage = mStageOrderOperator
+                    .getStageForLegacyPosition(SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                            true /*checkAllStagesIfNotActive*/);
+        } else {
+            topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+                    ? mSideStage
+                    : mMainStage;
+            bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
+                    ? mMainStage
+                    : mSideStage;
+        }
         (layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
                 bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer,
                 applyResizingOffset);
@@ -2082,10 +2429,22 @@
             return SPLIT_POSITION_UNDEFINED;
         }
 
-        if (mMainStage.containsToken(token)) {
-            return getMainStagePosition();
-        } else if (mSideStage.containsToken(token)) {
-            return getSideStagePosition();
+        if (enableFlexibleSplit()) {
+            // We could migrate to/return the new INDEX enums here since most callers just care that
+            // this value isn't SPLIT_POSITION_UNDEFINED, but
+            // ImePositionProcessor#getImeTargetPosition actually uses the leftTop/bottomRight value
+            StageTaskListener stageForToken = mStageOrderOperator.getAllStages().stream()
+                    .filter(stage -> stage.containsToken(token))
+                    .findFirst().orElse(null);
+            return stageForToken == null
+                    ? SPLIT_POSITION_UNDEFINED
+                    : mStageOrderOperator.getLegacyPositionForStage(stageForToken);
+        } else {
+            if (mMainStage.containsToken(token)) {
+                return getMainStagePosition();
+            } else if (mSideStage.containsToken(token)) {
+                return getSideStagePosition();
+            }
         }
 
         return SPLIT_POSITION_UNDEFINED;
@@ -2190,19 +2549,41 @@
                 ? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
     }
 
+    /**
+     * TODO(b/349828130) Currently the way this is being used is only to to get the bottomRight
+     *  stage. Eventually we'll need to rename and for now we'll repurpose the method to return
+     *  the bottomRight bounds under the flex split flag
+     */
     private void getSideStageBounds(Rect rect) {
-        if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+        if (enableFlexibleSplit()) {
+            // Split Layout doesn't actually keep track of the bounds based on the stage,
+            // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
+            // We'll then assume this method is to get bounds of bottomRight stage
+            mSplitLayout.getBounds2(rect);
+        }  else if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
             mSplitLayout.getBounds1(rect);
         } else {
             mSplitLayout.getBounds2(rect);
         }
     }
 
+    /**
+     * TODO(b/349828130) Currently the way this is being used is only to to get the leftTop
+     *  stage. Eventually we'll need to rename and for now we'll repurpose the method to return
+     *  the leftTop bounds under the flex split flag
+     */
     private void getMainStageBounds(Rect rect) {
-        if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
-            mSplitLayout.getBounds2(rect);
-        } else {
+        if (enableFlexibleSplit()) {
+            // Split Layout doesn't actually keep track of the bounds based on the stage,
+            // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
+            // We'll then assume this method is to get bounds of topLeft stage
             mSplitLayout.getBounds1(rect);
+        } else {
+            if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+                mSplitLayout.getBounds2(rect);
+            } else {
+                mSplitLayout.getBounds1(rect);
+            }
         }
     }
 
@@ -2211,14 +2592,23 @@
      * this task (yet) so this can also be used to identify which stage to put a task into.
      */
     private StageTaskListener getStageOfTask(ActivityManager.RunningTaskInfo taskInfo) {
-        // TODO(b/184679596): Find a way to either include task-org information in the transition,
-        //                    or synchronize task-org callbacks so we can use stage.containsTask
-        if (mMainStage.mRootTaskInfo != null
-                && taskInfo.parentTaskId == mMainStage.mRootTaskInfo.taskId) {
-            return mMainStage;
-        } else if (mSideStage.mRootTaskInfo != null
-                && taskInfo.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
-            return mSideStage;
+        if (enableFlexibleSplit()) {
+            return mStageOrderOperator.getActiveStages().stream()
+                    .filter((stage) -> stage.mRootTaskInfo != null &&
+                            taskInfo.parentTaskId == stage.mRootTaskInfo.taskId
+                    )
+                    .findFirst()
+                    .orElse(null);
+        } else {
+            // TODO(b/184679596): Find a way to either include task-org information in the
+            //  transition, or synchronize task-org callbacks so we can use stage.containsTask
+            if (mMainStage.mRootTaskInfo != null
+                    && taskInfo.parentTaskId == mMainStage.mRootTaskInfo.taskId) {
+                return mMainStage;
+            } else if (mSideStage.mRootTaskInfo != null
+                    && taskInfo.parentTaskId == mSideStage.mRootTaskInfo.taskId) {
+                return mSideStage;
+            }
         }
         return null;
     }
@@ -2226,7 +2616,11 @@
     @StageType
     private int getStageType(StageTaskListener stage) {
         if (stage == null) return STAGE_TYPE_UNDEFINED;
-        return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+        if (enableFlexibleSplit()) {
+            return stage.getId();
+        } else {
+            return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+        }
     }
 
     @Override
@@ -2273,11 +2667,17 @@
         if (isSplitActive()) {
             ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d split active",
                     request.getDebugId());
+            StageTaskListener primaryStage = enableFlexibleSplit()
+                    ? mStageOrderOperator.getActiveStages().get(0)
+                    : mMainStage;
+            StageTaskListener secondaryStage = enableFlexibleSplit()
+                    ? mStageOrderOperator.getActiveStages().get(1)
+                    : mSideStage;
             // Try to handle everything while in split-screen, so return a WCT even if it's empty.
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  split is active so using split"
                             + "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
                             + " sideChildren=%d", triggerTask.taskId, transitTypeToString(type),
-                    mMainStage.getChildCount(), mSideStage.getChildCount());
+                    primaryStage.getChildCount(), secondaryStage.getChildCount());
             out = new WindowContainerTransaction();
             if (stage != null) {
                 if (isClosingType(type) && stage.getChildCount() == 1) {
@@ -2317,11 +2717,21 @@
                     // the remote handler.
                     return null;
                 }
-
-                if ((mMainStage.containsTask(triggerTask.taskId)
-                            && mMainStage.getChildCount() == 1)
-                        || (mSideStage.containsTask(triggerTask.taskId)
-                            && mSideStage.getChildCount() == 1)) {
+                boolean anyStageContainsSingleFullscreenTask;
+                if (enableFlexibleSplit()) {
+                    anyStageContainsSingleFullscreenTask =
+                            mStageOrderOperator.getActiveStages().stream()
+                                    .anyMatch(stageListener ->
+                                            stageListener.containsTask(triggerTask.taskId)
+                                                    && stageListener.getChildCount() == 1);
+                } else {
+                    anyStageContainsSingleFullscreenTask =
+                            (mMainStage.containsTask(triggerTask.taskId)
+                                    && mMainStage.getChildCount() == 1)
+                                    || (mSideStage.containsTask(triggerTask.taskId)
+                                    && mSideStage.getChildCount() == 1);
+                }
+                if (anyStageContainsSingleFullscreenTask) {
                     // A splitting task is opening to fullscreen causes one side of the split empty,
                     // so appends operations to exit split.
                     prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
@@ -2341,11 +2751,19 @@
                 // One of the cases above handled it
                 return out;
             } else if (isSplitScreenVisible()) {
+                boolean allStagesHaveChildren;
+                if (enableFlexibleSplit()) {
+                    allStagesHaveChildren = runForActiveStagesAllMatch(stageTaskListener ->
+                            stageTaskListener.getChildCount() != 0);
+                } else {
+                    allStagesHaveChildren = mMainStage.getChildCount() != 0
+                            && mSideStage.getChildCount() != 0;
+                }
                 // If split is visible, only defer handling this transition if it's launching
                 // adjacent while there is already a split pair -- this may trigger PIP and
                 // that should be handled by the mixed handler.
                 final boolean deferTransition = requestHasLaunchAdjacentFlag(request)
-                    && mMainStage.getChildCount() != 0 && mSideStage.getChildCount() != 0;
+                    && allStagesHaveChildren;
                 return !deferTransition ? out : null;
             }
             // Don't intercept the transition if we are not handling it as a part of one of the
@@ -2585,8 +3003,15 @@
             }
 
             final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
-            if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
-                    || dismissStages.size() == 1) {
+            boolean anyStageHasNoChildren;
+            if (enableFlexibleSplit()) {
+                anyStageHasNoChildren = mStageOrderOperator.getActiveStages().stream()
+                        .anyMatch(stage -> stage.getChildCount() == 0);
+            } else {
+                anyStageHasNoChildren = mMainStage.getChildCount() == 0
+                        || mSideStage.getChildCount() == 0;
+            }
+            if (anyStageHasNoChildren || dismissStages.size() == 1) {
                 // If the size of dismissStages == 1, one of the task is closed without prepare
                 // pending transition, which could happen if all activities were finished after
                 // finish top activity in a task, so the trigger task is null when handleRequest.
@@ -2732,24 +3157,48 @@
             shouldAnimate = startPendingDismissAnimation(
                     dismiss, info, startTransaction, finishTransaction);
             if (shouldAnimate && dismiss.mReason == EXIT_REASON_DRAG_DIVIDER) {
-                final StageTaskListener toTopStage =
-                        dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
+                StageTaskListener toTopStage;
+                if (enableFlexibleSplit()) {
+                    toTopStage = mStageOrderOperator.getAllStages().stream()
+                            .filter(stage -> stage.getId() == dismiss.mDismissTop)
+                            .findFirst().orElseThrow();
+                } else {
+                    toTopStage = dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
+                }
                 mSplitTransitions.playDragDismissAnimation(transition, info, startTransaction,
                         finishTransaction, finishCallback, toTopStage.mRootTaskInfo.token,
                         toTopStage.getSplitDecorManager(), mRootTaskInfo.token);
                 return true;
             }
         } else if (mSplitTransitions.isPendingResize(transition)) {
+            Map<WindowContainerToken, SplitDecorManager> tokenDecorMap = new HashMap<>();
+            if (enableFlexibleSplit()) {
+                runForActiveStages(stageTaskListener ->
+                        tokenDecorMap.put(stageTaskListener.mRootTaskInfo.getToken(),
+                                stageTaskListener.getSplitDecorManager()));
+            } else {
+                tokenDecorMap.put(mMainStage.mRootTaskInfo.getToken(),
+                        mMainStage.getSplitDecorManager());
+                tokenDecorMap.put(mSideStage.mRootTaskInfo.getToken(),
+                        mSideStage.getSplitDecorManager());
+            }
             mSplitTransitions.playResizeAnimation(transition, info, startTransaction,
-                    finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
-                    mSideStage.mRootTaskInfo.token, mMainStage.getSplitDecorManager(),
-                    mSideStage.getSplitDecorManager());
+                    finishTransaction, finishCallback, tokenDecorMap);
             return true;
         }
         if (!shouldAnimate) return false;
 
+        WindowContainerToken mainToken;
+        WindowContainerToken sideToken;
+        if (enableFlexibleSplit()) {
+            mainToken = mStageOrderOperator.getActiveStages().get(0).mRootTaskInfo.token;
+            sideToken = mStageOrderOperator.getActiveStages().get(1).mRootTaskInfo.token;
+        } else {
+            mainToken = mMainStage.mRootTaskInfo.token;
+            sideToken = mSideStage.mRootTaskInfo.token;
+        }
         mSplitTransitions.playAnimation(transition, info, startTransaction, finishTransaction,
-                finishCallback, mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
+                finishCallback, mainToken, sideToken,
                 mRootTaskInfo.token);
         return true;
     }
@@ -2774,6 +3223,8 @@
         // First, verify that we actually have opened apps in both splits.
         TransitionInfo.Change mainChild = null;
         TransitionInfo.Change sideChild = null;
+        StageTaskListener firstAppStage = null;
+        StageTaskListener secondAppStage = null;
         final WindowContainerTransaction evictWct = new WindowContainerTransaction();
         for (int iC = 0; iC < info.getChanges().size(); ++iC) {
             final TransitionInfo.Change change = info.getChanges().get(iC);
@@ -2782,14 +3233,19 @@
             if (mPausingTasks.contains(taskInfo.taskId)) {
                 continue;
             }
-            final @StageType int stageType = getStageType(getStageOfTask(taskInfo));
-            if (mainChild == null && stageType == STAGE_TYPE_MAIN
+            StageTaskListener stage = getStageOfTask(taskInfo);
+            final @StageType int stageType = getStageType(stage);
+            if (mainChild == null
+                    && stageType == (enableFlexibleSplit() ? STAGE_TYPE_A : STAGE_TYPE_MAIN)
                     && (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
                 // Includes TRANSIT_CHANGE to cover reparenting top-most task to split.
                 mainChild = change;
-            } else if (sideChild == null && stageType == STAGE_TYPE_SIDE
+                firstAppStage = getStageOfTask(taskInfo);
+            } else if (sideChild == null
+                    && stageType == (enableFlexibleSplit() ? STAGE_TYPE_B : STAGE_TYPE_SIDE)
                     && (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
                 sideChild = change;
+                secondAppStage = stage;
             } else if (stageType != STAGE_TYPE_UNDEFINED && change.getMode() == TRANSIT_TO_BACK) {
                 // Collect all to back task's and evict them when transition finished.
                 evictWct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
@@ -2845,9 +3301,9 @@
         // TODO(b/184679596): Find a way to either include task-org information in
         //                    the transition, or synchronize task-org callbacks.
         final boolean mainNotContainOpenTask =
-                mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId);
+                mainChild != null && !firstAppStage.containsTask(mainChild.getTaskInfo().taskId);
         final boolean sideNotContainOpenTask =
-                sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId);
+                sideChild != null && !secondAppStage.containsTask(sideChild.getTaskInfo().taskId);
         if (mainNotContainOpenTask) {
             Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
                     + " to have been called with " + mainChild.getTaskInfo().taskId
@@ -2860,6 +3316,8 @@
         }
         final TransitionInfo.Change finalMainChild = mainChild;
         final TransitionInfo.Change finalSideChild = sideChild;
+        final StageTaskListener finalFirstAppStage = firstAppStage;
+        final StageTaskListener finalSecondAppStage = secondAppStage;
         enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
             if (!enterTransition.mResizeAnim) {
                 // If resizing, we'll call notify at the end of the resizing animation (below)
@@ -2867,16 +3325,18 @@
             }
             if (finalMainChild != null) {
                 if (!mainNotContainOpenTask) {
-                    mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+                    finalFirstAppStage.evictOtherChildren(callbackWct,
+                            finalMainChild.getTaskInfo().taskId);
                 } else {
-                    mMainStage.evictInvisibleChildren(callbackWct);
+                    finalFirstAppStage.evictInvisibleChildren(callbackWct);
                 }
             }
             if (finalSideChild != null) {
                 if (!sideNotContainOpenTask) {
-                    mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+                    finalSecondAppStage.evictOtherChildren(callbackWct,
+                            finalSideChild.getTaskInfo().taskId);
                 } else {
-                    mSideStage.evictInvisibleChildren(callbackWct);
+                    finalSecondAppStage.evictInvisibleChildren(callbackWct);
                 }
             }
             if (!evictWct.isEmpty()) {
@@ -2958,8 +3418,10 @@
     public void onPipExpandToSplit(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo taskInfo) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onPipExpandToSplit: task=%s", taskInfo);
+        // TODO(b/349828130) currently pass in index_undefined until we can revisit these
+        //  flex split + pip interactions in the future
         prepareEnterSplitScreen(wct, taskInfo, getActivateSplitPosition(taskInfo),
-                false /*resizeAnim*/);
+                false /*resizeAnim*/, SPLIT_INDEX_UNDEFINED);
 
         if (!isSplitScreenVisible() || mSplitRequest == null) {
             return;
@@ -3064,13 +3526,28 @@
         // Wait until after animation to update divider
 
         // Reset crops so they don't interfere with subsequent launches
-        t.setCrop(mMainStage.mRootLeash, null);
-        t.setCrop(mSideStage.mRootLeash, null);
+        if (enableFlexibleSplit()) {
+            runForActiveStages(stage -> t.setCrop(stage.mRootLeash, null /*crop*/));
+        } else {
+            t.setCrop(mMainStage.mRootLeash, null);
+            t.setCrop(mSideStage.mRootLeash, null);
+        }
         // Hide the non-top stage and set the top one to the fullscreen position.
         if (toStage != STAGE_TYPE_UNDEFINED) {
-            t.hide(toStage == STAGE_TYPE_MAIN ? mSideStage.mRootLeash : mMainStage.mRootLeash);
-            t.setPosition(toStage == STAGE_TYPE_MAIN
-                    ? mMainStage.mRootLeash : mSideStage.mRootLeash, 0, 0);
+            if (enableFlexibleSplit()) {
+                StageTaskListener stageToKeep = mStageOrderOperator.getAllStages().stream()
+                        .filter(stage -> stage.getId() == toStage)
+                        .findFirst().orElseThrow();
+                List<StageTaskListener> stagesToHide = mStageOrderOperator.getAllStages().stream()
+                        .filter(stage -> stage.getId() != toStage)
+                        .toList();
+                stagesToHide.forEach(stage -> t.hide(stage.mRootLeash));
+                t.setPosition(stageToKeep.mRootLeash, 0, 0);
+            } else {
+                t.hide(toStage == STAGE_TYPE_MAIN ? mSideStage.mRootLeash : mMainStage.mRootLeash);
+                t.setPosition(toStage == STAGE_TYPE_MAIN
+                        ? mMainStage.mRootLeash : mSideStage.mRootLeash, 0, 0);
+            }
         } else {
             for (int i = dismissingTasks.keySet().size() - 1; i >= 0; --i) {
                 finishT.hide(dismissingTasks.valueAt(i));
@@ -3085,8 +3562,12 @@
 
         // Hide divider and dim layer on transition finished.
         setDividerVisibility(false, t);
-        finishT.hide(mMainStage.mDimLayer);
-        finishT.hide(mSideStage.mDimLayer);
+        if (enableFlexibleSplit()) {
+            runForActiveStages(stage -> finishT.hide(stage.mRootLeash));
+        } else {
+            finishT.hide(mMainStage.mDimLayer);
+            finishT.hide(mSideStage.mDimLayer);
+        }
     }
 
     private boolean startPendingDismissAnimation(
@@ -3107,8 +3588,12 @@
             return false;
         }
         dismissTransition.setFinishedCallback((callbackWct, callbackT) -> {
-            mMainStage.getSplitDecorManager().release(callbackT);
-            mSideStage.getSplitDecorManager().release(callbackT);
+            if (enableFlexibleSplit()) {
+                runForActiveStages(stage -> stage.getSplitDecorManager().release(callbackT));
+            } else {
+                mMainStage.getSplitDecorManager().release(callbackT);
+                mSideStage.getSplitDecorManager().release(callbackT);
+            }
             callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
         });
         return true;
@@ -3125,8 +3610,15 @@
                 if (TransitionUtil.isClosingType(change.getMode())
                         && change.getTaskInfo() != null) {
                     final int taskId = change.getTaskInfo().taskId;
-                    if (mMainStage.getTopVisibleChildTaskId() == taskId
-                            || mSideStage.getTopVisibleChildTaskId() == taskId) {
+                    boolean anyStagesHaveTask;
+                    if (enableFlexibleSplit()) {
+                        anyStagesHaveTask = mStageOrderOperator.getActiveStages().stream()
+                                .anyMatch(stage -> stage.getTopVisibleChildTaskId() == taskId);
+                    } else {
+                        anyStagesHaveTask = mMainStage.getTopVisibleChildTaskId() == taskId
+                                || mSideStage.getTopVisibleChildTaskId() == taskId;
+                    }
+                    if (anyStagesHaveTask) {
                         mPausingTasks.add(taskId);
                     }
                 }
@@ -3158,9 +3650,16 @@
             final WindowContainerTransaction.HierarchyOp op =
                     finishWct.getHierarchyOps().get(i);
             final IBinder container = op.getContainer();
+            boolean anyStageContainsContainer;
+            if (enableFlexibleSplit()) {
+                anyStageContainsContainer = mStageOrderOperator.getActiveStages().stream()
+                        .anyMatch(stage -> stage.containsContainer(container));
+            } else {
+                anyStageContainsContainer = mMainStage.containsContainer(container)
+                        || mSideStage.containsContainer(container);
+            }
             if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
-                    && (mMainStage.containsContainer(container)
-                    || mSideStage.containsContainer(container))) {
+                    && anyStageContainsContainer) {
                 updateSurfaceBounds(mSplitLayout, finishT,
                         false /* applyResizingOffset */);
                 finishT.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
@@ -3187,10 +3686,18 @@
         // user entering recents.
         for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
             final int taskId = mPausingTasks.get(i);
-            if (mMainStage.containsTask(taskId)) {
-                mMainStage.evictChildren(finishWct, taskId);
-            } else if (mSideStage.containsTask(taskId)) {
-                mSideStage.evictChildren(finishWct, taskId);
+            if (enableFlexibleSplit()) {
+                mStageOrderOperator.getActiveStages().stream()
+                        .filter(stage -> stage.containsTask(taskId))
+                        .findFirst()
+                        .ifPresent(stageToEvict ->
+                            stageToEvict.evictChild(finishWct, taskId, "recentsPairToPair"));
+            } else {
+                if (mMainStage.containsTask(taskId)) {
+                    mMainStage.evictChild(finishWct, taskId, "recentsPairToPair");
+                } else if (mSideStage.containsTask(taskId)) {
+                    mSideStage.evictChild(finishWct, taskId, "recentsPairToPair");
+                }
             }
         }
         // If pending enter hasn't consumed, the mix handler will invoke start pending
@@ -3253,8 +3760,15 @@
      */
     private void setSplitsVisible(boolean visible) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setSplitsVisible: visible=%b", visible);
-        mMainStage.mVisible = mSideStage.mVisible = visible;
-        mMainStage.mHasChildren = mSideStage.mHasChildren = visible;
+        if (enableFlexibleSplit()) {
+            runForActiveStages(stage -> {
+                stage.mVisible = visible;
+                stage.mHasChildren = visible;
+            });
+        } else {
+            mMainStage.mVisible = mSideStage.mVisible = visible;
+            mMainStage.mHasChildren = mSideStage.mHasChildren = visible;
+        }
     }
 
     /**
@@ -3297,6 +3811,10 @@
      * executed.
      */
     private void logExitToStage(@ExitReason int exitReason, boolean toMainStage) {
+        if (enableFlexibleSplit()) {
+            // TODO(b/374825718) update logging for 2+ apps
+            return;
+        }
         mLogger.logExit(exitReason,
                 toMainStage ? getMainStagePosition() : SPLIT_POSITION_UNDEFINED,
                 toMainStage ? mMainStage.getTopChildTaskUid() : 0 /* mainStageUid */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
new file mode 100644
index 0000000..b7b3c9b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt
@@ -0,0 +1,185 @@
+/*
+ * 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.splitscreen
+
+import android.content.Context
+import com.android.internal.protolog.ProtoLog
+import com.android.launcher3.icons.IconProvider
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_NONE
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_2
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
+import com.android.wm.shell.shared.split.SplitScreenConstants.SnapPosition
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex
+import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_A
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_B
+import com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_C
+import com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString
+import com.android.wm.shell.windowdecor.WindowDecorViewModel
+import java.util.Optional
+
+/**
+ * Responsible for creating [StageTaskListener]s and maintaining their ordering on screen.
+ * Must be notified whenever stages positions change via swapping or starting/ending tasks
+ */
+class StageOrderOperator (
+        context: Context,
+        taskOrganizer: ShellTaskOrganizer,
+        displayId: Int,
+        stageCallbacks: StageTaskListener.StageListenerCallbacks,
+        syncQueue: SyncTransactionQueue,
+        iconProvider: IconProvider,
+        windowDecorViewModel: Optional<WindowDecorViewModel>
+    ) {
+
+    private val MAX_STAGES = 3
+    /**
+     * This somewhat acts as a replacement to stageTypes in the intermediary, so we want to start
+     * it after the @StageType constant values just to be safe and avoid potentially subtle bugs.
+     */
+    private var stageIds = listOf(STAGE_TYPE_A, STAGE_TYPE_B, STAGE_TYPE_C)
+
+    /**
+     * Active Stages, this list represent the current, ordered list of stages that are
+     * currently visible to the user. This map should be empty if the user is currently
+     * not in split screen. Note that this is different than if split screen is visible, which
+     * is determined by [StageListenerImpl.mVisible].
+     * Split stages can be active and in the background
+     */
+    val activeStages = mutableListOf<StageTaskListener>()
+    val allStages = mutableListOf<StageTaskListener>()
+    var isActive: Boolean = false
+    var isVisible: Boolean = false
+    @SnapPosition private var currentLayout: Int = SNAP_TO_NONE
+
+    init {
+        for(i in 0 until MAX_STAGES) {
+            allStages.add(StageTaskListener(context,
+                taskOrganizer,
+                displayId,
+                stageCallbacks,
+                syncQueue,
+                iconProvider,
+                windowDecorViewModel,
+                stageIds[i])
+            )
+        }
+    }
+
+    /**
+     * Updates internal state to keep record of "active" stages. Note that this does NOT call
+     * [StageTaskListener.activate] on the stages.
+     */
+    fun onEnteringSplit(@SnapPosition goingToLayout: Int) {
+        if (goingToLayout == currentLayout) {
+            // Add protolog here. Return for now, but maybe we want to handle swap case, TBD
+            return
+        }
+        val freeStages: List<StageTaskListener> =
+            allStages.filterNot { activeStages.contains(it) }
+        when(goingToLayout) {
+            SplitScreenConstants.SNAP_TO_2_50_50 -> {
+                if (activeStages.size < 2) {
+                    // take from allStages and add into activeStages
+                    for (i in 0 until (2 - activeStages.size)) {
+                        val stage = freeStages[i]
+                        activeStages.add(stage)
+                    }
+                }
+            }
+        }
+        ProtoLog.d(
+            ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+            "Activated stages: %d ids=%s",
+            activeStages.size,
+            activeStages.joinToString(",") { stageTypeToString(it.id) }
+        )
+        isActive = true
+    }
+
+    fun onExitingSplit() {
+        activeStages.clear()
+        isActive = false
+    }
+
+    /**
+     * Given a legacy [SplitPosition] returns one of the stages from the actives stages.
+     * If there are no active stages and [checkAllStagesIfNotActive] is not true, then will return
+     * null
+     */
+    fun getStageForLegacyPosition(@SplitPosition position: Int,
+                                  checkAllStagesIfNotActive : Boolean = false) :
+            StageTaskListener? {
+        if (activeStages.size != 2 && !checkAllStagesIfNotActive) {
+            return null
+        }
+        val listToCheck = if (activeStages.isEmpty() and checkAllStagesIfNotActive)
+            allStages else
+            activeStages
+        if (position == SPLIT_POSITION_TOP_OR_LEFT) {
+            return listToCheck[0]
+        } else if (position == SPLIT_POSITION_BOTTOM_OR_RIGHT) {
+            return listToCheck[1]
+        } else {
+            throw IllegalArgumentException("No stage for invalid position")
+        }
+    }
+
+    /**
+     * Returns a legacy split position for the given stage. If no stages are active then this will
+     * return [SPLIT_POSITION_UNDEFINED]
+     */
+    @SplitPosition
+    fun getLegacyPositionForStage(stage: StageTaskListener) : Int {
+        if (allStages[0] == stage) {
+            return SPLIT_POSITION_TOP_OR_LEFT
+        } else if (allStages[1] == stage) {
+            return SPLIT_POSITION_BOTTOM_OR_RIGHT
+        } else {
+            return SPLIT_POSITION_UNDEFINED
+        }
+    }
+
+    /**
+     * Returns the stageId from a given splitIndex. This will default to checking from all stages if
+     * [isActive] is false, otherwise will only check active stages.
+     */
+    fun getStageForIndex(@SplitIndex splitIndex: Int) : StageTaskListener {
+        // Probably should do a check for index to be w/in the bounds of the current split layout
+        // that we're currently in
+        val listToCheck = if (isActive) activeStages else allStages
+        if (splitIndex == SPLIT_INDEX_0) {
+            return listToCheck[0]
+        } else if (splitIndex == SPLIT_INDEX_1) {
+            return listToCheck[1]
+        } else if (splitIndex == SPLIT_INDEX_2) {
+            return listToCheck[2]
+        } else {
+            // Though I guess what if we're adding to the end? Maybe that indexing needs to be
+            // resolved elsewhere
+            throw IllegalStateException("No stage for the given splitIndex")
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 4407e5b..4a37169 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -22,14 +22,17 @@
 import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE;
+import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
 
 import android.annotation.CallSuper;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.TaskInfo;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.IBinder;
@@ -71,6 +74,8 @@
     // No current way to enforce this but if enableFlexibleSplit() is enabled, then only 1 of the
     // stages should have this be set/being used
     private boolean mIsActive;
+    /** Unique identifier for this state, > 0 */
+    @StageType private final int mId;
     /** Callback interface for listening to changes in a split-screen stage. */
     public interface StageListenerCallbacks {
         void onRootTaskAppeared();
@@ -109,13 +114,14 @@
     StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
             StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
             IconProvider iconProvider,
-            Optional<WindowDecorViewModel> windowDecorViewModel) {
+            Optional<WindowDecorViewModel> windowDecorViewModel, int id) {
         mContext = context;
         mCallbacks = callbacks;
         mSyncQueue = syncQueue;
         mIconProvider = iconProvider;
         mWindowDecorViewModel = windowDecorViewModel;
         taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
+        mId = id;
     }
 
     int getChildCount() {
@@ -138,6 +144,8 @@
      * Returns the top visible child task's id.
      */
     int getTopVisibleChildTaskId() {
+        // TODO(b/378601156): This doesn't get the top task (translucent tasks are also
+        //  visible-requested)
         final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible
                 && t.isVisibleRequested);
         return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
@@ -147,6 +155,7 @@
      * Returns the top activity uid for the top child task.
      */
     int getTopChildTaskUid() {
+        // TODO(b/378601156): This doesn't get the top task
         final ActivityManager.RunningTaskInfo taskInfo =
                 getChildTaskInfo(t -> t.topActivityInfo != null);
         return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0;
@@ -157,6 +166,11 @@
         return contains(t -> t.isFocused);
     }
 
+    @StageType
+    int getId() {
+        return mId;
+    }
+
     private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) {
         if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) {
             return true;
@@ -193,10 +207,10 @@
     @CallSuper
     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskAppeared: taskId=%d taskParent=%d rootTask=%d "
-                        + "taskActivity=%s",
+                        + "stageId=%s taskActivity=%s",
                 taskInfo.taskId, taskInfo.parentTaskId,
                 mRootTaskInfo != null ? mRootTaskInfo.taskId : -1,
-                taskInfo.baseActivity);
+                stageTypeToString(mId), taskInfo.baseActivity);
         if (mRootTaskInfo == null) {
             mRootLeash = leash;
             mRootTaskInfo = taskInfo;
@@ -226,8 +240,9 @@
     @Override
     @CallSuper
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s",
-                taskInfo.taskId, taskInfo.baseActivity);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s "
+                        + "stageId=%s",
+                taskInfo.taskId, taskInfo.baseActivity, stageTypeToString(mId));
         mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
         if (mRootTaskInfo.taskId == taskInfo.taskId) {
             mRootTaskInfo = taskInfo;
@@ -257,7 +272,8 @@
     @Override
     @CallSuper
     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d", taskInfo.taskId);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskVanished: task=%d stageId=%s",
+                taskInfo.taskId, stageTypeToString(mId));
         final int taskId = taskInfo.taskId;
         mWindowDecorViewModel.ifPresent(vm -> vm.onTaskVanished(taskInfo));
         if (mRootTaskInfo.taskId == taskId) {
@@ -379,10 +395,9 @@
 
     /** Collects all the current child tasks and prepares transaction to evict them to display. */
     void evictAllChildren(WindowContainerTransaction wct) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evicting all children");
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
-            wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+            evictChild(wct, taskInfo, "all");
         }
     }
 
@@ -390,13 +405,11 @@
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
             if (taskId == taskInfo.taskId) continue;
-            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict other child: task=%d", taskId);
-            wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+            evictChild(wct, taskInfo, "other");
         }
     }
 
     void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "evictNonOpeningChildren");
         final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone();
         for (int i = 0; i < apps.length; i++) {
             if (apps[i].mode == MODE_OPENING) {
@@ -405,8 +418,7 @@
         }
         for (int i = toBeEvict.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = toBeEvict.valueAt(i);
-            ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict non-opening child: task=%d", taskInfo.taskId);
-            wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+            evictChild(wct, taskInfo, "non-opening");
         }
     }
 
@@ -414,21 +426,30 @@
         for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
             final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
             if (!taskInfo.isVisible) {
-                ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict invisible child: task=%d",
-                        taskInfo.taskId);
-                wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+                evictChild(wct, taskInfo, "invisible");
             }
         }
     }
 
-    void evictChildren(WindowContainerTransaction wct, int taskId) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d", taskId);
+    void evictChild(WindowContainerTransaction wct, int taskId, String reason) {
         final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId);
         if (taskInfo != null) {
-            wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+            evictChild(wct, taskInfo, reason);
         }
     }
 
+    private void evictChild(@NonNull WindowContainerTransaction wct, @NonNull TaskInfo taskInfo,
+            @NonNull String reason) {
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d reason=%s", taskInfo.taskId,
+                reason);
+        // We are reparenting the task, but not removing the task from mChildrenTaskInfo, so to
+        // prevent this task from being considered as a top task for the roots, we need to override
+        // the visibility of the soon-to-be-hidden task
+        taskInfo.isVisible = false;
+        taskInfo.isVisibleRequested = false;
+        wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+    }
+
     void reparentTopTask(WindowContainerTransaction wct) {
         wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token,
                 CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES,
@@ -457,14 +478,17 @@
     }
 
     void activate(WindowContainerTransaction wct, boolean includingTopTask) {
-        if (mIsActive) return;
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b",
-                includingTopTask);
+        if (mIsActive && !enableFlexibleSplit()) return;
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b stage=%s",
+                includingTopTask, stageTypeToString(mId));
 
         if (includingTopTask) {
             reparentTopTask(wct);
         }
 
+        if (enableFlexibleSplit()) {
+            return;
+        }
         mIsActive = true;
     }
 
@@ -472,11 +496,14 @@
         deactivate(wct, false /* toTop */);
     }
 
-    void deactivate(WindowContainerTransaction wct, boolean toTop) {
-        if (!mIsActive) return;
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: toTop=%b rootTaskInfo=%s",
-                toTop, mRootTaskInfo);
-        mIsActive = false;
+    void deactivate(WindowContainerTransaction wct, boolean reparentTasksToTop) {
+        if (!mIsActive && !enableFlexibleSplit()) return;
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: reparentTasksToTop=%b "
+                        + "rootTaskInfo=%s stage=%s",
+                reparentTasksToTop, mRootTaskInfo, stageTypeToString(mId));
+        if (!enableFlexibleSplit()) {
+            mIsActive = false;
+        }
 
         if (mRootTaskInfo == null) return;
         final WindowContainerToken rootToken = mRootTaskInfo.token;
@@ -485,14 +512,15 @@
                 null /* newParent */,
                 null /* windowingModes */,
                 null /* activityTypes */,
-                toTop);
+                reparentTasksToTop);
     }
 
     // --------
-    // Previously only used in SideStage
+    // Previously only used in SideStage. With flexible split this is called for all stages
     boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
-        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b",
-                mChildrenTaskInfo.size(), toTop);
+        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b "
+                        + " stageI=%s",
+                mChildrenTaskInfo.size(), toTop, stageTypeToString(mId));
         if (mChildrenTaskInfo.size() == 0) return false;
         wct.reparentTasks(
                 mRootTaskInfo.token,
@@ -513,6 +541,15 @@
     }
 
     @Override
+    public String toString() {
+        return "mId: " + stageTypeToString(mId)
+                + " mVisible: " + mVisible
+                + " mActive: " + mIsActive
+                + " mHasRootTask: " + mHasRootTask
+                + " childSize: " + mChildrenTaskInfo.size();
+    }
+
+    @Override
     @CallSuper
     public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index d28287d..32f3cd8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -334,8 +334,8 @@
 
             // Sides adjacent to split bar or task bar are not be animated.
             Insets margins;
-            final boolean isLandscape = mRootStageBounds.width() > mRootStageBounds.height();
-            if (isLandscape) { // Left and right splits.
+            final boolean isLeftRightSplit = mSplitScreenController.get().get().isLeftRightSplit();
+            if (isLeftRightSplit) {
                 margins = getLandscapeMargins(margin, taskbarExpanded);
             } else { // Top and bottom splits.
                 margins = getPortraitMargins(margin, taskbarExpanded);
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/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
new file mode 100644
index 0000000..6c8cc68
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.BringDesktopAppsToFront
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/** 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/MinimizeAutoPipAppWindowTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.kt
new file mode 100644
index 0000000..48befc0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MinimizeAutoPipAppWindowTest.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.MinimizeAutoPipAppWindow
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [MinimizeAutoPipAppWindow]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class MinimizeAutoPipAppWindowTest : MinimizeAutoPipAppWindow()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.kt
new file mode 100644
index 0000000..9462f15
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenUnlimitedAppsTest.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.OpenUnlimitedApps
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [OpenUnlimitedApps]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class OpenUnlimitedAppsTest : OpenUnlimitedApps()
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..8d04749 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,8 @@
 
     @Test
     open fun enterDesktopWithDrag() {
-        testApp.enterDesktopWithDrag(wmHelper, device)
+        // By default this method uses drag to desktop
+        testApp.enterDesktopMode(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
index a2b88f2..60a0fb5 100644
--- 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
@@ -59,7 +59,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/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/MinimizeAutoPipAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.kt
new file mode 100644
index 0000000..d6c3266
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAutoPipAppWindow.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.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
+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 minimizing the app entering pip on leave automatically */
+@Ignore("Test Base Class")
+abstract class MinimizeAutoPipAppWindow {
+    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))
+    private val pipApp = PipAppHelper(instrumentation)
+    private val pipAppDesktopMode = DesktopModeAppHelper(pipApp)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        Assume.assumeTrue(Flags.enableMinimizeButton())
+        testApp.enterDesktopMode(wmHelper, device)
+        pipApp.launchViaIntent(wmHelper)
+        pipApp.enableAutoEnterForPipActivity()
+    }
+
+    @Test
+    open fun minimizePipAppWindow() {
+        pipAppDesktopMode.minimizeDesktopApp(wmHelper, device, isPip = true)
+    }
+
+    @After
+    fun teardown() {
+        pipApp.exit(wmHelper)
+        testApp.exit(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..a246326 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
@@ -23,12 +23,10 @@
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
 import com.android.server.wm.flicker.helpers.MailAppHelper
-import com.android.server.wm.flicker.helpers.NewTasksAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.window.flags.Flags
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import org.junit.After
 import org.junit.Assume
 import org.junit.Before
@@ -51,32 +49,30 @@
 
     private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
     private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
-    private val newTasksApp = DesktopModeAppHelper(NewTasksAppHelper(instrumentation))
-    private val imeApp = DesktopModeAppHelper(ImeAppHelper(instrumentation))
-    private val letterboxAppHelper = DesktopModeAppHelper(LetterboxAppHelper(instrumentation))
+
+    private val maxNum = DesktopModeStatus.getMaxTaskLimit(instrumentation.context)
 
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        testApp.enterDesktopWithDrag(wmHelper, device)
-        mailApp.launchViaIntent(wmHelper)
-        newTasksApp.launchViaIntent(wmHelper)
-        imeApp.launchViaIntent(wmHelper)
+        Assume.assumeTrue(maxNum > 0)
+        testApp.enterDesktopMode(wmHelper, device)
+        // Launch new [maxNum-1] tasks, which ends up opening [maxNum] tasks in total.
+        for (i in 1..maxNum - 1) {
+            mailApp.launchViaIntent(wmHelper)
+        }
     }
 
     @Test
     open fun openAppToMinimizeWindow() {
-        // Launch a new app while 4 apps are already open on desktop. This should result in the
-        // first app we opened to be minimized.
-        letterboxAppHelper.launchViaIntent(wmHelper)
+        // Launch a new tasks, which ends up opening [maxNum]+1 tasks in total. This should
+        // result in the first app we opened to be minimized.
+        mailApp.launchViaIntent(wmHelper)
     }
 
     @After
     fun teardown() {
         testApp.exit(wmHelper)
         mailApp.exit(wmHelper)
-        newTasksApp.exit(wmHelper)
-        imeApp.exit(wmHelper)
-        letterboxAppHelper.exit(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/OpenUnlimitedApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
new file mode 100644
index 0000000..367c4a4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenUnlimitedApps.kt
@@ -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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+/**
+ * Base scenario test for opening many apps on the device without the window limit.
+ */
+@Ignore("Test Base Class")
+abstract class OpenUnlimitedApps()
+{
+    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))
+    private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+
+    private val maxNum = DesktopModeStatus.getMaxTaskLimit(instrumentation.context)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        Assume.assumeTrue(maxNum == 0)
+        testApp.enterDesktopMode(wmHelper, device)
+    }
+
+    @Test
+    open fun openUnlimitedApps() {
+        // The maximum number of active tasks is infinite. We here use 12 as a large enough number.
+        val openTaskNum = 12
+
+        // Launch new [openTaskNum] tasks.
+        for (i in 1..openTaskNum) {
+            mailApp.launchViaIntent(wmHelper)
+        }
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+        mailApp.exit(wmHelper)
+    }
+}
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/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index a248303..fd4328d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -16,16 +16,18 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
 import android.tools.flicker.subject.exceptions.IncorrectRegionException
 import android.tools.flicker.subject.layers.LayerSubject
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -35,6 +37,7 @@
 import org.junit.runners.Parameterized
 import kotlin.math.abs
 
+
 /**
  * Test entering pip from an app via auto-enter property when navigating to home.
  *
@@ -60,6 +63,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index df952c9..d4ad4ef8 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -17,10 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.traces.component.ComponentNameMatcher
+import com.android.wm.shell.Flags
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -52,6 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) :
     AutoEnterPipOnGoToHomeTest(flicker) {
     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 302b8c4..cc6e4b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
@@ -53,6 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 77a1edb..53725fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -17,9 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -52,6 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.closePipWindow(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 6e32d64..a1551b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,9 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -43,6 +45,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 9a6cb61..ea5b3e5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -19,6 +19,7 @@
 import android.app.Activity
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -32,6 +33,7 @@
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -68,6 +70,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     private val testApp = FixedOrientationAppHelper(instrumentation)
     private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index 6b4751c..a109c4b 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -16,9 +16,11 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -49,6 +51,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.clickEnterPipButton(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 8d0bc0f..14ec303 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -16,9 +16,11 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -51,6 +53,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
     ExitPipToAppTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 939f328..8a34b5e 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -16,9 +16,11 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -50,6 +52,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 258663b..4f189fc 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -17,12 +17,14 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.traces.component.ComponentNameMatcher
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -54,6 +56,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.doubleClickPipWindow(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 1964e3c..4d72b03d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -17,11 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -33,6 +35,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index 5f8ac2a..1c40d89 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -16,7 +16,10 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -24,10 +27,9 @@
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.toFlickerComponent
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -62,6 +64,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class FromSplitScreenAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
     AutoEnterPipOnGoToHomeTest(flicker) {
     private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 48c85a8..12e2328 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -16,7 +16,10 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -24,10 +27,9 @@
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.toFlickerComponent
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
@@ -63,6 +65,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
     EnterPipTransition(flicker) {
     private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index ee62cf5..d979b42 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -17,10 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
 import org.junit.FixMethodOrder
@@ -56,6 +58,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class MovePipDownOnShelfHeightChange(flicker: LegacyFlickerTest) :
     MovePipShelfHeightTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index 04fedf4..88d78ed 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -27,6 +28,7 @@
 import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -41,6 +43,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     private val imeApp = ImeAppHelper(instrumentation)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 4d643f7..c533800 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -17,10 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
 import org.junit.FixMethodOrder
@@ -56,6 +58,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) :
     MovePipShelfHeightTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
@@ -65,7 +68,8 @@
     }
 
     /** Checks that the visible region of [pipApp] window always moves up during the animation. */
-    @Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
+    @Presubmit
+    @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
 
     /** Checks that the visible region of [pipApp] layer always moves up during the animation. */
     @Presubmit @Test fun pipLayerMovesUp() = pipLayerMoves(Direction.UP)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 429774f..04016a9 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -17,11 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -33,6 +35,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.changeAspectRatio(wmHelper) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index a4df69f..6bcaabc 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -18,11 +18,13 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -35,6 +37,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     private var isDraggedLeft: Boolean = true
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index cbd4a52..d82bfdd 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,16 +17,18 @@
 package com.android.wm.shell.flicker.pip
 
 import android.graphics.Rect
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.flicker.rules.RemoveAllTasksButHomeRule
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -40,6 +42,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     // represents the direction in which the pip window should be snapping
     private var willSnapRight: Boolean = true
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 16d08e5..dbc97d0 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -17,13 +17,15 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.flicker.subject.exceptions.IncorrectRegionException
-import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -36,6 +38,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     override val thisTransition: FlickerBuilder.() -> Unit = {
         transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index 578a9b5..9d46ac1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -17,8 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.app.Activity
+import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.Rotation
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
@@ -26,10 +29,9 @@
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import android.tools.helpers.WindowUtils
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import org.junit.Assume
@@ -48,6 +50,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
     private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index c6cf341..e72251f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsDisabled
 import android.tools.flicker.assertions.FlickerTest
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
@@ -25,6 +26,7 @@
 import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.Flags
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -58,6 +60,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
 class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
     private val testApp = SimpleAppHelper(instrumentation)
     private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index bc2bfdb..c37bf35 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
 import android.tools.Rotation
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
@@ -31,9 +32,14 @@
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.wm.shell.flicker.BaseTest
 import com.google.common.truth.Truth
+import org.junit.Rule
 import org.junit.Test
 
 abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+    @JvmField
+    @Rule
+    val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
     protected val pipApp = PipAppHelper(instrumentation)
     protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
     protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
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/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 2319716..5df3957 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,18 +90,20 @@
 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.DesktopModeEntryExitTransitionListener
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
 import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
+import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
+import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
 import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler
 import com.android.wm.shell.desktopmode.persistence.Desktop
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
@@ -120,11 +116,11 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN
 import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED
 import com.android.wm.shell.splitscreen.SplitScreenController
 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
@@ -208,12 +204,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
@@ -224,23 +218,23 @@
   @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
+  @Mock
+  lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener
   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()
 
@@ -263,6 +257,7 @@
         mockitoSession()
             .strictness(Strictness.LENIENT)
             .spyStatic(DesktopModeStatus::class.java)
+            .spyStatic(Toast::class.java)
             .startMocking()
     doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
@@ -290,6 +285,7 @@
     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
@@ -304,11 +300,7 @@
     controller = createController()
     controller.setSplitScreenController(splitScreenController)
     controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter
-
-    doAnswer {
-      keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler)
-      null
-    }.whenever(mockInputManager).registerKeyGestureEventHandler(any())
+    controller.desktopModeEnterExitTransitionListener = desktopModeEnterExitTransitionListener
 
     shellInit.init()
 
@@ -343,8 +335,6 @@
         dragToDesktopTransitionHandler,
         mMockDesktopImmersiveController,
         taskRepository,
-        desktopModeLoggerTransitionObserver,
-        launchAdjacentController,
         recentsTransitionHandler,
         multiInstanceHelper,
         shellExecutor,
@@ -352,8 +342,6 @@
         recentTasksController,
         mockInteractionJankMonitor,
         mockHandler,
-        mockInputManager,
-        mockFocusTransitionObserver,
         desktopModeEventLogger,
         desktopTilingDecorViewModel,
       )
@@ -1073,6 +1061,7 @@
     controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1084,12 +1073,14 @@
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
         .isEqualTo(WINDOWING_MODE_UNDEFINED)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
   fun moveTaskToDesktop_nonExistentTask_doesNothing() {
     controller.moveTaskToDesktop(999, transitionSource = UNKNOWN)
     verifyEnterDesktopWCTNotExecuted()
+    verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(anyInt())
   }
 
   @Test
@@ -1134,9 +1125,9 @@
       }
 
     controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
-
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1151,6 +1142,9 @@
 
     controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
     verifyEnterDesktopWCTNotExecuted()
+    verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(
+      FREEFORM_ANIMATION_DURATION
+    )
   }
 
   @Test
@@ -1197,6 +1191,7 @@
 
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1216,6 +1211,7 @@
       assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
           .isEqualTo(WINDOWING_MODE_FREEFORM)
     }
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1236,6 +1232,7 @@
       assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
           .isEqualTo(WINDOWING_MODE_FREEFORM)
     }
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1257,6 +1254,7 @@
       assertThat(hierarchyOps.map { it.container })
           .doesNotContain(freeformTaskSecond.token.asBinder())
     }
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
   }
 
   @Test
@@ -1265,6 +1263,7 @@
     controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
     verify(splitScreenController)
         .prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
   }
@@ -1275,6 +1274,7 @@
     controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
     val wct = getLatestEnterDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
     verify(splitScreenController, never())
         .prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
   }
@@ -1289,6 +1289,7 @@
     controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)
 
     val wct = getLatestEnterDesktopWct()
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
     assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 1) // visible tasks + home
     wct.assertReorderAt(0, homeTask)
     wct.assertReorderSequenceInRange(
@@ -1307,6 +1308,7 @@
     controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)
 
     val wct = getLatestEnterDesktopWct()
+    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
     assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 2) // tasks + home + wallpaper
     // Move home to front
     wct.assertReorderAt(0, homeTask)
@@ -1326,6 +1328,7 @@
     tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
     controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
     val wct = getLatestExitDesktopWct()
+    verify(desktopModeEnterExitTransitionListener, times(1)).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
         .isEqualTo(WINDOWING_MODE_UNDEFINED)
   }
@@ -1343,6 +1346,7 @@
 
     val wct = getLatestExitDesktopWct()
     val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
+    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
     assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
     // Removes wallpaper activity when leaving desktop
     wct.assertRemoveAt(index = 0, wallpaperToken)
@@ -1357,6 +1361,7 @@
     val wct = getLatestExitDesktopWct()
     assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
         .isEqualTo(WINDOWING_MODE_FULLSCREEN)
+    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
   }
 
   @Test
@@ -1373,6 +1378,7 @@
     val wct = getLatestExitDesktopWct()
     val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
     assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
+    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
     // Removes wallpaper activity when leaving desktop
     wct.assertRemoveAt(index = 0, wallpaperToken)
   }
@@ -1393,6 +1399,7 @@
     val wct = getLatestExitDesktopWct()
     val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
     assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
+    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
     // Does not remove wallpaper activity, as desktop still has a visible desktop task
     assertThat(wct.hierarchyOps).isEmpty()
   }
@@ -1407,13 +1414,13 @@
   fun moveToFullscreen_secondDisplayTaskHasFreeform_secondDisplayNotAffected() {
     val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
     val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY)
-
     controller.moveToFullscreen(taskDefaultDisplay.taskId, transitionSource = UNKNOWN)
 
     with(getLatestExitDesktopWct()) {
       assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
       assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
     }
+    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
   }
 
   @Test
@@ -1558,44 +1565,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()
@@ -3190,7 +3159,7 @@
     runOpenNewWindow(task)
     verify(splitScreenController)
       .startIntent(any(), anyInt(), any(), any(),
-        optionsCaptor.capture(), anyOrNull(), eq(true)
+        optionsCaptor.capture(), anyOrNull(), eq(true), eq(SPLIT_INDEX_UNDEFINED)
       )
     assertThat(ActivityOptions.fromBundle(optionsCaptor.value).launchWindowingMode)
       .isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
@@ -3206,7 +3175,7 @@
     verify(splitScreenController)
       .startIntent(
         any(), anyInt(), any(), any(),
-        optionsCaptor.capture(), anyOrNull(), eq(true)
+        optionsCaptor.capture(), anyOrNull(), eq(true), eq(SPLIT_INDEX_UNDEFINED)
       )
     assertThat(ActivityOptions.fromBundle(optionsCaptor.value).launchWindowingMode)
       .isEqualTo(WINDOWING_MODE_MULTI_WINDOW)
@@ -3465,7 +3434,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
     }
@@ -3474,7 +3443,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
@@ -3493,14 +3462,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(
@@ -3520,6 +3489,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 {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 2cfce69..0cf15ba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -24,6 +24,7 @@
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
 import static com.android.wm.shell.draganddrop.DragTestUtils.createAppClipData;
 import static com.android.wm.shell.draganddrop.DragTestUtils.createIntentClipData;
 import static com.android.wm.shell.draganddrop.DragTestUtils.createTaskInfo;
@@ -226,7 +227,7 @@
 
         mPolicy.onDropped(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
         verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
-                eq(SPLIT_POSITION_UNDEFINED), any(), any());
+                eq(SPLIT_POSITION_UNDEFINED), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
     }
 
     private void dragOverFullscreenApp_expectSplitScreenTargets(ClipData data) {
@@ -241,12 +242,12 @@
 
         mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
-                eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
+                eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
         reset(mSplitScreenStarter);
 
         mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
     }
 
     private void dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(ClipData data) {
@@ -261,13 +262,13 @@
 
         mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
-                eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
+                eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
         reset(mSplitScreenStarter);
 
         mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
                 null /* hideTaskToken */);
         verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any(), eq(SPLIT_INDEX_UNDEFINED));
     }
 
     @Test
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/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 966651f..72a7a3f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -23,6 +23,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 
@@ -200,10 +201,11 @@
                 PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
 
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
-                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+                SPLIT_INDEX_0);
 
         verify(mStageCoordinator).startIntent(eq(pendingIntent), mIntentCaptor.capture(),
-                eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull());
+                eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull(), eq(SPLIT_INDEX_0));
         assertEquals(FLAG_ACTIVITY_NO_USER_ACTION,
                 mIntentCaptor.getValue().getFlags() & FLAG_ACTIVITY_NO_USER_ACTION);
     }
@@ -220,10 +222,11 @@
         doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask(any());
 
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
-                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+                SPLIT_INDEX_0);
 
         verify(mStageCoordinator).startIntent(eq(pendingIntent), mIntentCaptor.capture(),
-                eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull());
+                eq(SPLIT_POSITION_TOP_OR_LEFT), isNull(), isNull(), eq(SPLIT_INDEX_0));
         assertEquals(FLAG_ACTIVITY_MULTIPLE_TASK,
                 mIntentCaptor.getValue().getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK);
     }
@@ -243,10 +246,11 @@
         doReturn(sameTaskInfo).when(mRecentTasks).findTaskInBackground(any(), anyInt(), any());
 
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
-                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+                SPLIT_INDEX_0);
 
         verify(mStageCoordinator).startTask(anyInt(), eq(SPLIT_POSITION_TOP_OR_LEFT),
-                isNull(), isNull());
+                isNull(), isNull(), eq(SPLIT_INDEX_0));
         verify(mMultiInstanceHelper, never()).supportsMultiInstanceSplit(any());
         verify(mStageCoordinator, never()).switchSplitPosition(any());
     }
@@ -269,10 +273,11 @@
                 .findTaskInBackground(any(), anyInt(), any());
 
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
-                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+                SPLIT_INDEX_0);
         verify(mMultiInstanceHelper, never()).supportsMultiInstanceSplit(any());
         verify(mStageCoordinator).startTask(anyInt(), eq(SPLIT_POSITION_TOP_OR_LEFT),
-                isNull(), isNull());
+                isNull(), isNull(), eq(SPLIT_INDEX_0));
     }
 
     @Test
@@ -289,7 +294,8 @@
                 SPLIT_POSITION_BOTTOM_OR_RIGHT);
 
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
-                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */);
+                SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
+                SPLIT_INDEX_0);
 
         verify(mStageCoordinator).switchSplitPosition(anyString());
     }
@@ -301,7 +307,7 @@
                 PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
                 SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
-                true /* forceLaunchNewTask */);
+                true /* forceLaunchNewTask */, SPLIT_INDEX_0);
         verify(mRecentTasks, never()).findTaskInBackground(any(), anyInt(), any());
     }
 
@@ -312,7 +318,7 @@
                 PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
         mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
                 SPLIT_POSITION_TOP_OR_LEFT, null /* options */, null /* hideTaskToken */,
-                false /* forceLaunchNewTask */);
+                false /* forceLaunchNewTask */, SPLIT_INDEX_0);
         verify(mRecentTasks).findTaskInBackground(any(), anyInt(), any());
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index ce3944a..e32cf38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -27,6 +27,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 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_DRAG_DIVIDER;
@@ -133,11 +134,11 @@
         mSplitLayout = SplitTestUtils.createMockSplitLayout();
         mMainStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
                 StageTaskListener.StageListenerCallbacks.class), mSyncQueue,
-                mIconProvider, Optional.of(mWindowDecorViewModel)));
+                mIconProvider, Optional.of(mWindowDecorViewModel), STAGE_TYPE_MAIN));
         mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
         mSideStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
                 StageTaskListener.StageListenerCallbacks.class), mSyncQueue,
-                mIconProvider, Optional.of(mWindowDecorViewModel)));
+                mIconProvider, Optional.of(mWindowDecorViewModel), STAGE_TYPE_SIDE));
         mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
                 mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a252a9d..2d102fb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -165,8 +166,9 @@
         final WindowContainerTransaction wct = spy(new WindowContainerTransaction());
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        // TODO(b/349828130) Address this once we remove index_undefined called
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
         verify(mMainStage).reparentTopTask(eq(wct));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
         assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getMainStagePosition());
@@ -183,8 +185,9 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        // TODO(b/349828130) Address this once we remove index_undefined called
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getMainStagePosition());
         assertEquals(SPLIT_POSITION_TOP_OR_LEFT, mStageCoordinator.getSideStagePosition());
     }
@@ -195,8 +198,9 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
         mStageCoordinator.moveToStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+        // TODO(b/349828130) Address this once we remove index_undefined called
         verify(mStageCoordinator).prepareEnterSplitScreen(eq(wct), eq(task),
-                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false));
+                eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), eq(false), eq(SPLIT_INDEX_UNDEFINED));
         assertEquals(SPLIT_POSITION_BOTTOM_OR_RIGHT, mStageCoordinator.getSideStagePosition());
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 7144a1e..fe91440 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -19,6 +19,8 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertFalse;
@@ -93,7 +95,8 @@
                 mCallbacks,
                 mSyncQueue,
                 mIconProvider,
-                Optional.of(mWindowDecorViewModel));
+                Optional.of(mWindowDecorViewModel),
+                STAGE_TYPE_UNDEFINED);
         mRootTask = new TestRunningTaskInfoBuilder().build();
         mRootTask.parentTaskId = INVALID_TASK_ID;
         mSurfaceControl = new SurfaceControl.Builder().setName("test").build();
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/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index d993b87..4330f0a 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -28,12 +28,14 @@
 #define INDENT "  "
 #define INDENT2 "    "
 
+namespace android {
+
 namespace {
+
 // Time to spend fading out the pointer completely.
 const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
-} // namespace
 
-namespace android {
+} // namespace
 
 // --- MouseCursorController ---
 
@@ -64,17 +66,21 @@
     mLocked.pointerSprite.clear();
 }
 
-void MouseCursorController::move(float deltaX, float deltaY) {
+vec2 MouseCursorController::move(float deltaX, float deltaY) {
 #if DEBUG_MOUSE_CURSOR_UPDATES
     ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
 #endif
     if (deltaX == 0.0f && deltaY == 0.0f) {
-        return;
+        return {};
     }
 
+    // When transition occurs, the MouseCursorController object may or may not be deleted, depending
+    // if there's another display on the other side of the transition. At this point we still need
+    // to move the cursor to the boundary.
     std::scoped_lock lock(mLock);
-
-    setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
+    const vec2 pos{mLocked.pointerX + deltaX, mLocked.pointerY + deltaY};
+    setPositionLocked(pos.x, pos.y);
+    return vec2{pos.x - mLocked.pointerX, pos.y - mLocked.pointerY};
 }
 
 void MouseCursorController::setPosition(float x, float y) {
@@ -82,22 +88,26 @@
     ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
 #endif
     std::scoped_lock lock(mLock);
+
     setPositionLocked(x, y);
 }
 
-void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
-    const auto& v = mLocked.viewport;
-    if (!v.isValid()) return;
-
+FloatRect MouseCursorController::getBoundsLocked() REQUIRES(mLock) {
     // The valid bounds for a mouse cursor. Since the right and bottom edges are considered outside
     // the display, clip the bounds by one pixel instead of letting the cursor get arbitrarily
     // close to the outside edge.
-    const FloatRect bounds{
+    return FloatRect{
             static_cast<float>(mLocked.viewport.logicalLeft),
             static_cast<float>(mLocked.viewport.logicalTop),
             static_cast<float>(mLocked.viewport.logicalRight - 1),
             static_cast<float>(mLocked.viewport.logicalBottom - 1),
     };
+}
+void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
+    const auto& v = mLocked.viewport;
+    if (!v.isValid()) return;
+
+    const FloatRect bounds = getBoundsLocked();
     mLocked.pointerX = std::max(bounds.left, std::min(bounds.right, x));
     mLocked.pointerY = std::max(bounds.top, std::min(bounds.bottom, y));
 
diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h
index 12b31a8..10f0d76 100644
--- a/libs/input/MouseCursorController.h
+++ b/libs/input/MouseCursorController.h
@@ -20,9 +20,6 @@
 #include <gui/DisplayEventReceiver.h>
 #include <input/DisplayViewport.h>
 #include <input/Input.h>
-#include <utils/BitSet.h>
-#include <utils/Looper.h>
-#include <utils/RefBase.h>
 
 #include <functional>
 #include <map>
@@ -43,7 +40,8 @@
     MouseCursorController(PointerControllerContext& context);
     ~MouseCursorController();
 
-    void move(float deltaX, float deltaY);
+    // Move the pointer and return unconsumed delta
+    vec2 move(float deltaX, float deltaY);
     void setPosition(float x, float y);
     FloatPoint getPosition() const;
     ui::LogicalDisplayId getDisplayId() const;
@@ -113,6 +111,7 @@
     bool doFadingAnimationLocked(nsecs_t timestamp);
 
     void startAnimationLocked();
+    FloatRect getBoundsLocked();
 };
 
 } // namespace android
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 78d7d3a..59397da 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -138,15 +138,18 @@
     return mDisplayInfoListener->mLock;
 }
 
-void PointerController::move(float deltaX, float deltaY) {
+vec2 PointerController::move(float deltaX, float deltaY) {
     const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
-    vec2 transformed;
+    ui::Transform transform;
     {
         std::scoped_lock lock(getLock());
-        const auto& transform = getTransformForDisplayLocked(displayId);
-        transformed = transformWithoutTranslation(transform, {deltaX, deltaY});
+        transform = getTransformForDisplayLocked(displayId);
     }
-    mCursorController.move(transformed.x, transformed.y);
+
+    vec2 transformed = transformWithoutTranslation(transform, {deltaX, deltaY});
+
+    vec2 unconsumedDelta = mCursorController.move(transformed.x, transformed.y);
+    return transformWithoutTranslation(transform.inverse(), unconsumedDelta);
 }
 
 void PointerController::setPosition(float x, float y) {
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index ee8d121..69bef54 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -51,7 +51,7 @@
 
     ~PointerController() override;
 
-    void move(float deltaX, float deltaY) override;
+    vec2 move(float deltaX, float deltaY) override;
     void setPosition(float x, float y) override;
     FloatPoint getPosition() const override;
     ui::LogicalDisplayId getDisplayId() const override;
@@ -165,7 +165,7 @@
 
     ~TouchPointerController() override;
 
-    void move(float, float) override {
+    vec2 move(float, float) override {
         LOG_ALWAYS_FATAL("Should not be called");
     }
     void setPosition(float, float) override {
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 5b00fca..80c934a 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -40,6 +40,8 @@
     CURSOR_TYPE_CUSTOM = -1,
 };
 
+static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
+
 using ::testing::AllOf;
 using ::testing::Field;
 using ::testing::NiceMock;
@@ -399,6 +401,135 @@
                          testing::Values(PointerControllerInterface::ControllerType::MOUSE,
                                          PointerControllerInterface::ControllerType::STYLUS));
 
+class MousePointerControllerTest : public PointerControllerTest {
+protected:
+    MousePointerControllerTest() {
+        sp<MockSprite> testPointerSprite(new NiceMock<MockSprite>);
+        EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testPointerSprite));
+
+        // create a mouse pointer controller
+        mPointerController =
+                PointerController::create(mPolicy, mLooper, *mSpriteController,
+                                          PointerControllerInterface::ControllerType::MOUSE);
+
+        // set display viewport
+        DisplayViewport viewport;
+        viewport.displayId = ui::LogicalDisplayId::DEFAULT;
+        viewport.logicalRight = 5;
+        viewport.logicalBottom = 5;
+        viewport.physicalRight = 5;
+        viewport.physicalBottom = 5;
+        viewport.deviceWidth = 5;
+        viewport.deviceHeight = 5;
+        mPointerController->setDisplayViewport(viewport);
+    }
+};
+
+struct MousePointerControllerTestParam {
+    vec2 startPosition;
+    vec2 delta;
+    vec2 endPosition;
+    vec2 unconsumedDelta;
+};
+
+class PointerControllerViewportTransitionTest
+      : public MousePointerControllerTest,
+        public testing::WithParamInterface<MousePointerControllerTestParam> {};
+
+TEST_P(PointerControllerViewportTransitionTest, testPointerViewportTransition) {
+    const auto& params = GetParam();
+
+    mPointerController->setPosition(params.startPosition.x, params.startPosition.y);
+    auto unconsumedDelta = mPointerController->move(params.delta.x, params.delta.y);
+
+    auto position = mPointerController->getPosition();
+    EXPECT_NEAR(position.x, params.endPosition.x, EPSILON);
+    EXPECT_NEAR(position.y, params.endPosition.y, EPSILON);
+    EXPECT_NEAR(unconsumedDelta.x, params.unconsumedDelta.x, EPSILON);
+    EXPECT_NEAR(unconsumedDelta.y, params.unconsumedDelta.y, EPSILON);
+}
+
+INSTANTIATE_TEST_SUITE_P(PointerControllerViewportTransitionTest,
+                         PointerControllerViewportTransitionTest,
+                         testing::Values(
+                                 // no transition
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {2.0f, 2.0f},
+                                                                 {4.0f, 4.0f},
+                                                                 {0.0f, 0.0f}},
+                                 // right boundary
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {3.0f, 0.0f},
+                                                                 {4.0f, 2.0f},
+                                                                 {1.0f, 0.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {3.0f, -1.0f},
+                                                                 {4.0f, 1.0f},
+                                                                 {1.0f, 0.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {3.0f, 1.0f},
+                                                                 {4.0f, 3.0f},
+                                                                 {1.0f, 0.0f}},
+                                 // left boundary
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-3.0f, 0.0f},
+                                                                 {0.0f, 2.0f},
+                                                                 {-1.0f, 0.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-3.0f, -1.0f},
+                                                                 {0.0f, 1.0f},
+                                                                 {-1.0f, 0.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-3.0f, 1.0f},
+                                                                 {0.0f, 3.0f},
+                                                                 {-1.0f, 0.0f}},
+                                 // bottom boundary
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {0.0f, 3.0f},
+                                                                 {2.0f, 4.0f},
+                                                                 {0.0f, 1.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-1.0f, 3.0f},
+                                                                 {1.0f, 4.0f},
+                                                                 {0.0f, 1.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {1.0f, 3.0f},
+                                                                 {3.0f, 4.0f},
+                                                                 {0.0f, 1.0f}},
+                                 // top boundary
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {0.0f, -3.0f},
+                                                                 {2.0f, 0.0f},
+                                                                 {0.0f, -1.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-1.0f, -3.0f},
+                                                                 {1.0f, 0.0f},
+                                                                 {0.0f, -1.0f}},
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {1.0f, -3.0f},
+                                                                 {3.0f, 0.0f},
+                                                                 {0.0f, -1.0f}},
+                                 // top-left corner
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-3.0f, -3.0f},
+                                                                 {0.0f, 0.0f},
+                                                                 {-1.0f, -1.0f}},
+                                 // top-right corner
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {3.0f, -3.0f},
+                                                                 {4.0f, 0.0f},
+                                                                 {1.0f, -1.0f}},
+                                 // bottom-right corner
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {3.0f, 3.0f},
+                                                                 {4.0f, 4.0f},
+                                                                 {1.0f, 1.0f}},
+                                 // bottom-left corner
+                                 MousePointerControllerTestParam{{2.0f, 2.0f},
+                                                                 {-3.0f, 3.0f},
+                                                                 {0.0f, 4.0f},
+                                                                 {-1.0f, 1.0f}}));
+
 class PointerControllerWindowInfoListenerTest : public Test {};
 
 TEST_F(PointerControllerWindowInfoListenerTest,
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 da50f2c..c085b89 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -41,6 +41,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -59,6 +60,8 @@
     public static final int PLAYER_UPID_INVALID = -1;
     /** @hide */
     public static final int PLAYER_DEVICEID_INVALID = 0;
+    /** @hide */
+    public static final int[] PLAYER_DEVICEIDS_INVALID = new int[0];
 
     // information about the implementation
     /**
@@ -335,7 +338,7 @@
     private final Object mUpdateablePropLock = new Object();
 
     @GuardedBy("mUpdateablePropLock")
-    private int mDeviceId;
+    private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
     @GuardedBy("mUpdateablePropLock")
     private int mSessionId;
     @GuardedBy("mUpdateablePropLock")
@@ -364,7 +367,7 @@
         mClientUid = uid;
         mClientPid = pid;
         mMutedState = 0;
-        mDeviceId = PLAYER_DEVICEID_INVALID;
+        mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
         mPlayerState = PLAYER_STATE_IDLE;
         mPlayerAttr = pic.mAttributes;
         if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -388,10 +391,11 @@
     }
 
     // sets the fields that are updateable and require synchronization
-    private void setUpdateableFields(int deviceId, int sessionId, int mutedState, FormatInfo format)
+    private void setUpdateableFields(int[] deviceIds, int sessionId, int mutedState,
+            FormatInfo format)
     {
         synchronized (mUpdateablePropLock) {
-            mDeviceId = deviceId;
+            mDeviceIds = deviceIds;
             mSessionId = sessionId;
             mMutedState = mutedState;
             mFormatInfo = format;
@@ -427,7 +431,7 @@
         anonymCopy.mClientPid = PLAYER_UPID_INVALID;
         anonymCopy.mIPlayerShell = null;
         anonymCopy.setUpdateableFields(
-                /*deviceId*/ PLAYER_DEVICEID_INVALID,
+                /*deviceIds*/ new int[0],
                 /*sessionId*/ AudioSystem.AUDIO_SESSION_ALLOCATE,
                 /*mutedState*/ 0,
                 FormatInfo.DEFAULT);
@@ -471,14 +475,14 @@
     @Deprecated
     @FlaggedApi(FLAG_ROUTED_DEVICE_IDS)
     public @Nullable AudioDeviceInfo getAudioDeviceInfo() {
-        final int deviceId;
+        final int[] deviceIds;
         synchronized (mUpdateablePropLock) {
-            deviceId = mDeviceId;
+            deviceIds = mDeviceIds;
         }
-        if (deviceId == PLAYER_DEVICEID_INVALID) {
+        if (deviceIds.length == 0) {
             return null;
         }
-        return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+        return AudioManager.getDeviceForPortId(deviceIds[0], AudioManager.GET_DEVICES_OUTPUTS);
     }
 
     /**
@@ -491,9 +495,17 @@
     @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);
+        final int[] deviceIds;
+        synchronized (mUpdateablePropLock) {
+            deviceIds = mDeviceIds;
+        }
+
+        for (int i = 0; i < deviceIds.length; i++) {
+            AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+                    AudioManager.GET_DEVICES_OUTPUTS);
+            if (audioDeviceInfo != null) {
+                audioDeviceInfos.add(audioDeviceInfo);
+            }
         }
         return audioDeviceInfos;
     }
@@ -701,15 +713,15 @@
      * @hide
      * Handle a player state change
      * @param event
-     * @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
-     * <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or
-     * <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when
-     * <br>pausing or stopping playback. It will be set to active device when playback starts or
+     * @param deviceIds an array of device ids. This can be empty.
+     * <br>Note device ids are non-empty for {@code PLAYER_UPDATE_DEVICE_ID} or
+     * <br>{@code PLAYER_STATE_STARTED} events, as the device ids will be emptied when pausing
+     * <br>or stopping playback. It will be set to active devices when playback starts or
      * <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the
-     * <br>device changes in the middle of playback.
+     * <br>devices change in the middle of playback.
      * @return true if the state changed, false otherwise
      */
-    public boolean handleStateEvent(int event, int deviceId) {
+    public boolean handleStateEvent(int event, int[] deviceIds) {
         boolean changed = false;
         synchronized (mUpdateablePropLock) {
 
@@ -720,8 +732,8 @@
             }
 
             if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
-                changed = changed || (mDeviceId != deviceId);
-                mDeviceId = deviceId;
+                changed = changed || !Arrays.equals(mDeviceIds, deviceIds);
+                mDeviceIds = deviceIds;
             }
 
             if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
@@ -801,8 +813,8 @@
     @Override
     public int hashCode() {
         synchronized (mUpdateablePropLock) {
-            return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid,
-                    mClientPid, mSessionId);
+            return Objects.hash(mPlayerIId, Arrays.toString(mDeviceIds), mMutedState, mPlayerType,
+                    mClientUid, mClientPid, mSessionId);
         }
     }
 
@@ -815,7 +827,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         synchronized (mUpdateablePropLock) {
             dest.writeInt(mPlayerIId);
-            dest.writeInt(mDeviceId);
+            dest.writeIntArray(mDeviceIds);
             dest.writeInt(mMutedState);
             dest.writeInt(mPlayerType);
             dest.writeInt(mClientUid);
@@ -834,7 +846,10 @@
 
     private AudioPlaybackConfiguration(Parcel in) {
         mPlayerIId = in.readInt();
-        mDeviceId = in.readInt();
+        mDeviceIds = new int[in.readInt()];
+        for (int i = 0; i < mDeviceIds.length; i++) {
+            mDeviceIds[i] = in.readInt();
+        }
         mMutedState = in.readInt();
         mPlayerType = in.readInt();
         mClientUid = in.readInt();
@@ -855,7 +870,7 @@
         AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
 
         return ((mPlayerIId == that.mPlayerIId)
-                && (mDeviceId == that.mDeviceId)
+                && Arrays.equals(mDeviceIds, that.mDeviceIds)
                 && (mMutedState == that.mMutedState)
                 && (mPlayerType == that.mPlayerType)
                 && (mClientUid == that.mClientUid)
@@ -868,7 +883,7 @@
         StringBuilder apcToString = new StringBuilder();
         synchronized (mUpdateablePropLock) {
             apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
-                    " deviceId:").append(mDeviceId).append(" type:").append(
+                    " deviceIds:").append(Arrays.toString(mDeviceIds)).append(" type:").append(
                     toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(
                     mClientUid).append(
                     "/").append(mClientPid).append(" state:").append(
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 9394941..cacd59f 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1908,17 +1908,37 @@
     }
 
     /**
+     * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+     */
+    private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        final int[] deviceIds = native_getRoutedDeviceIds();
+        if (deviceIds == null || deviceIds.length == 0) {
+            return audioDeviceInfos;
+        }
+
+        for (int i = 0; i < deviceIds.length; i++) {
+            AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+                    AudioManager.GET_DEVICES_INPUTS);
+            if (audioDeviceInfo != null) {
+                audioDeviceInfos.add(audioDeviceInfo);
+            }
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
      * <code>getRoutedDevice()</code> will return null.
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
-        int deviceId = native_getRoutedDeviceId();
-        if (deviceId == 0) {
+        final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+        if (audioDeviceInfos.isEmpty()) {
             return null;
         }
-        return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+        return audioDeviceInfos.get(0);
     }
 
     /**
@@ -1930,12 +1950,7 @@
     @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;
+        return getRoutedDevicesInternal();
     }
 
     /**
@@ -2513,7 +2528,7 @@
             int sampleRateInHz, int channelCount, int audioFormat);
 
     private native final boolean native_setInputDevice(int deviceId);
-    private native final int native_getRoutedDeviceId();
+    private native int[] native_getRoutedDeviceIds();
     private native final void native_enableDeviceCallback();
     private native final void native_disableDeviceCallback();
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 93a1831..a5d9adb 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -3023,7 +3023,7 @@
             }
         }
         synchronized(mPlayStateLock) {
-            baseStart(0); // unknown device at this point
+            baseStart(new int[0]); // unknown device at this point
             native_start();
             // FIXME see b/179218630
             //baseStart(native_getRoutedDeviceId());
@@ -3784,6 +3784,26 @@
     }
 
     /**
+     * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+     */
+    private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        final int[] deviceIds = native_getRoutedDeviceIds();
+        if (deviceIds == null || deviceIds.length == 0) {
+            return audioDeviceInfos;
+        }
+
+        for (int i = 0; i < deviceIds.length; i++) {
+            AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+                    AudioManager.GET_DEVICES_OUTPUTS);
+            if (audioDeviceInfo != null) {
+                audioDeviceInfos.add(audioDeviceInfo);
+            }
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
      * 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.
@@ -3792,11 +3812,11 @@
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
-        int deviceId = native_getRoutedDeviceId();
-        if (deviceId == 0) {
+        final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+        if (audioDeviceInfos.isEmpty()) {
             return null;
         }
-        return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+        return audioDeviceInfos.get(0);
     }
 
     /**
@@ -3808,12 +3828,7 @@
     @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;
+        return getRoutedDevicesInternal();
     }
 
     private void tryToDisableNativeRoutingCallback() {
@@ -3973,7 +3988,7 @@
      */
     private void broadcastRoutingChange() {
         AudioManager.resetAudioPortGeneration();
-        baseUpdateDeviceId(getRoutedDevice());
+        baseUpdateDeviceIds(getRoutedDevicesInternal());
         synchronized (mRoutingChangeListeners) {
             for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
                 delegate.notifyClient();
@@ -4530,7 +4545,7 @@
     private native final int native_setAuxEffectSendLevel(float level);
 
     private native final boolean native_setOutputDevice(int deviceId);
-    private native final int native_getRoutedDeviceId();
+    private native int[] native_getRoutedDeviceIds();
     private native final void native_enableDeviceCallback();
     private native final void native_disableDeviceCallback();
 
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index 167ab65..68a3aa7 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -145,7 +145,14 @@
                 mAudioAttributes);
         if (isPlaying()) {
             // FIXME: b/174876389 clean up device id reporting
-            baseStart(getDeviceId());
+            // Set as deviceIds empty and create an array with element if device id is valid.
+            int[] deviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
+            int deviceId = getDeviceId();
+            if (deviceId != 0) {
+                deviceIds = new int[1];
+                deviceIds[0] = deviceId;
+            }
+            baseStart(deviceIds);
         }
     }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9fd3f5b..08b0dd3 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -87,7 +87,7 @@
 
     oneway void playerAttributes(in int piid, in AudioAttributes attr);
 
-    oneway void playerEvent(in int piid, in int event, in int eventId);
+    oneway void playerEvent(in int piid, in int event, in int[] eventId);
 
     oneway void releasePlayer(in int piid);
 
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/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 96edd63..782db35 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1876,6 +1876,8 @@
      * Codecs with this security model is not included in
      * {@link MediaCodecList#REGULAR_CODECS}, but included in
      * {@link MediaCodecList#ALL_CODECS}.
+     *
+     * @hide
      */
     @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
     public static final int SECURITY_MODEL_TRUSTED_CONTENT_ONLY = 2;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index bd65b2e..bc09aee 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1748,6 +1748,7 @@
             (1 << MediaCodecInfo.SECURITY_MODEL_MEMORY_SAFE);
     /**
      * Flag for {@link MediaCodecInfo#SECURITY_MODEL_TRUSTED_CONTENT_ONLY}.
+     * @hide
      */
     @FlaggedApi(FLAG_IN_PROCESS_SW_AUDIO_CODEC)
     public static final int FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY =
@@ -1759,8 +1760,7 @@
      * The associated value is a flag of the following values:
      * {@link FLAG_SECURITY_MODEL_SANDBOXED},
      * {@link FLAG_SECURITY_MODEL_MEMORY_SAFE},
-     * {@link FLAG_SECURITY_MODEL_TRUSTED_CONTENT_ONLY}. The default value is
-     * {@link FLAG_SECURITY_MODEL_SANDBOXED}.
+     * The default value is {@link FLAG_SECURITY_MODEL_SANDBOXED}.
      * <p>
      * When passed to {@link MediaCodecList#findDecoderForFormat} or
      * {@link MediaCodecList#findEncoderForFormat}, MediaCodecList filters
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 158bc7f..f1c2a7a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1415,7 +1415,7 @@
     }
 
     private void startImpl() {
-        baseStart(0); // unknown device at this point
+        baseStart(new int[0]); // unknown device at this point
         stayAwake(true);
         tryToEnableNativeRoutingCallback();
         _start();
@@ -1541,6 +1541,26 @@
     }
 
     /**
+     * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+     */
+    private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        final int[] deviceIds = native_getRoutedDeviceIds();
+        if (deviceIds == null || deviceIds.length == 0) {
+            return audioDeviceInfos;
+        }
+
+        for (int i = 0; i < deviceIds.length; i++) {
+            AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+                    AudioManager.GET_DEVICES_OUTPUTS);
+            if (audioDeviceInfo != null) {
+                audioDeviceInfos.add(audioDeviceInfo);
+            }
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
      * Returns an {@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 device can be null or correspond to previously
@@ -1550,11 +1570,11 @@
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
-        int deviceId = native_getRoutedDeviceId();
-        if (deviceId == 0) {
+        final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+        if (audioDeviceInfos.isEmpty()) {
             return null;
         }
-        return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS);
+        return audioDeviceInfos.get(0);
     }
 
     /**
@@ -1567,12 +1587,7 @@
     @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;
+        return getRoutedDevicesInternal();
     }
 
     /**
@@ -1584,7 +1599,7 @@
             // Prevent the case where an event is triggered by registering a routing change
             // listener via the media player.
             if (mEnableSelfRoutingMonitor) {
-                baseUpdateDeviceId(getRoutedDevice());
+                baseUpdateDeviceIds(getRoutedDevicesInternal());
             }
             for (NativeRoutingEventHandlerDelegate delegate
                     : mRoutingChangeListeners.values()) {
@@ -1694,7 +1709,7 @@
     }
 
     private native final boolean native_setOutputDevice(int deviceId);
-    private native final int native_getRoutedDeviceId();
+    private native int[] native_getRoutedDeviceIds();
     private native final void native_enableDeviceCallback(boolean enabled);
 
     /**
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f75bcf3..7af78b8 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1684,6 +1684,26 @@
     }
 
     /**
+     * Internal API of getRoutedDevices(). We should not call flag APIs internally.
+     */
+    private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() {
+        List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>();
+        final int[] deviceIds = native_getRoutedDeviceIds();
+        if (deviceIds == null || deviceIds.length == 0) {
+            return audioDeviceInfos;
+        }
+
+        for (int i = 0; i < deviceIds.length; i++) {
+            AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i],
+                    AudioManager.GET_DEVICES_INPUTS);
+            if (audioDeviceInfo != null) {
+                audioDeviceInfos.add(audioDeviceInfo);
+            }
+        }
+        return audioDeviceInfos;
+    }
+
+    /**
      * Returns an {@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 device can be null or correspond to previously
@@ -1691,11 +1711,11 @@
      */
     @Override
     public AudioDeviceInfo getRoutedDevice() {
-        int deviceId = native_getRoutedDeviceId();
-        if (deviceId == 0) {
+        final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal();
+        if (audioDeviceInfos.isEmpty()) {
             return null;
         }
-        return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS);
+        return audioDeviceInfos.get(0);
     }
 
     /**
@@ -1708,12 +1728,7 @@
     @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;
+        return getRoutedDevicesInternal();
     }
 
     /*
@@ -1773,7 +1788,7 @@
     }
 
     private native final boolean native_setInputDevice(int deviceId);
-    private native final int native_getRoutedDeviceId();
+    private native int[] native_getRoutedDeviceIds();
     private native final void native_enableDeviceCallback(boolean enabled);
 
     //--------------------------------------------------------------------------
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 3f44b09..dbf8338ac 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -39,6 +39,8 @@
 import com.android.internal.app.IAppOpsService;
 
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -91,7 +93,7 @@
     @GuardedBy("mLock")
     private float mVolMultiplier = 1.0f;
     @GuardedBy("mLock")
-    private int mDeviceId;
+    private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID;
 
     /**
      * Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -158,35 +160,36 @@
         }
     }
 
-    void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
-        int deviceId = 0;
-        if (deviceInfo != null) {
-            deviceId = deviceInfo.getId();
+    void baseUpdateDeviceIds(@NonNull List<AudioDeviceInfo> deviceInfos) {
+        int[] deviceIds = new int[deviceInfos.size()];
+        for (int i = 0; i < deviceInfos.size(); i++) {
+            deviceIds[i] = deviceInfos.get(i).getId();
         }
+
         int piid;
         synchronized (mLock) {
             piid = mPlayerIId;
-            mDeviceId = deviceId;
+            mDeviceIds = deviceIds;
         }
         try {
             getService().playerEvent(piid,
-                    AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
+                    AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceIds);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, "
-                    + deviceId
+                    + Arrays.toString(deviceIds)
                     + " device id will not be tracked for piid=" + piid, e);
         }
     }
 
-    private void updateState(int state, int deviceId) {
+    private void updateState(int state, @NonNull int[] deviceIds) {
         final int piid;
         synchronized (mLock) {
             mState = state;
             piid = mPlayerIId;
-            mDeviceId = deviceId;
+            mDeviceIds = deviceIds;
         }
         try {
-            getService().playerEvent(piid, state, deviceId);
+            getService().playerEvent(piid, state, deviceIds);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, "
                     + AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -194,11 +197,12 @@
         }
     }
 
-    void baseStart(int deviceId) {
+    void baseStart(@NonNull int[] deviceIds) {
         if (DEBUG) {
-            Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
+            Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId="
+                    + Arrays.toString(deviceIds));
         }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceIds);
     }
 
     void baseSetStartDelayMs(int delayMs) {
@@ -215,12 +219,12 @@
 
     void basePause() {
         if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, new int[0]);
     }
 
     void baseStop() {
         if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, new int[0]);
     }
 
     void baseSetPan(float pan) {
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 7b9ff23..f22cc9c 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -317,7 +317,7 @@
         // FIXME: b/174876164 implement device id for soundpool
         try {
             Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play");
-            baseStart(0);
+            baseStart(new int[0]);
             return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index 5b1ea8b..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,37 +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: "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"
@@ -94,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 {
@@ -109,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."
@@ -144,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 5c11def..273f21e 100644
--- a/media/java/android/media/quality/AmbientBacklightEvent.java
+++ b/media/java/android/media/quality/AmbientBacklightEvent.java
@@ -40,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.
@@ -69,9 +69,9 @@
     private final AmbientBacklightMetadata mMetadata;
 
     /**
-     * Constructor of AmbientBacklightEvent.
+     * Constructs AmbientBacklightEvent.
      */
-    public AmbientBacklightEvent(int eventType,
+    public AmbientBacklightEvent(@Type int eventType,
             @Nullable AmbientBacklightMetadata metadata) {
         mEventType = eventType;
         mMetadata = metadata;
@@ -85,6 +85,7 @@
     /**
      * Gets event type.
      */
+    @Type
     public int getEventType() {
         return mEventType;
     }
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java
index 9c11f9a..5cea10d 100644
--- a/media/java/android/media/quality/AmbientBacklightMetadata.java
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.java
@@ -29,6 +29,9 @@
 
 /**
  * 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
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
@@ -44,10 +47,15 @@
     private final int[] mZonesColors;
 
     /**
-     * Constructor of AmbientBacklightMetadata.
+     * Constructs AmbientBacklightMetadata.
      */
-    public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm,
-            int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber,
+    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;
@@ -69,7 +77,7 @@
     }
 
     /**
-     * Gets package name.
+     * Gets package name of the metadata.
      * @hide
      */
     @NonNull
@@ -102,7 +110,9 @@
     }
 
     /**
-     * Gets the number of lights in each horizontal zone.
+     * 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() {
@@ -110,7 +120,9 @@
     }
 
     /**
-     * Gets the number of lights in each vertical zone.
+     * 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() {
@@ -118,10 +130,11 @@
     }
 
     /**
+     * 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 4ed7bc7..d904cf7 100644
--- a/media/java/android/media/quality/AmbientBacklightSettings.java
+++ b/media/java/android/media/quality/AmbientBacklightSettings.java
@@ -30,7 +30,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Settings for ambient backlight.
+ * Settings to configure ambient backlight hardware.
  * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
@@ -124,8 +124,13 @@
     /**
      * Constructs AmbientBacklightSettings.
      */
-    public AmbientBacklightSettings(int source, int maxFps, int colorFormat,
-            int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted,
+    public AmbientBacklightSettings(
+            @Source int source,
+            int maxFps,
+            @PixelFormat.Format int colorFormat,
+            int horizontalZonesNumber,
+            int verticalZonesNumber,
+            boolean isLetterboxOmitted,
             int threshold) {
         mSource = source;
         mMaxFps = maxFps;
@@ -171,7 +176,9 @@
     }
 
     /**
-     * Gets the number of lights in each horizontal zone.
+     * 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() {
@@ -179,7 +186,9 @@
     }
 
     /**
-     * Gets the number of lights in each vertical zone.
+     * 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() {
@@ -187,7 +196,11 @@
     }
 
     /**
-     * Returns {@code true} if letter box is omitted; {@code false} otherwise.
+     * 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() {
@@ -195,6 +208,10 @@
     }
 
     /**
+     * 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() {
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/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java
index f07ef87..5fec86a 100644
--- a/media/java/android/media/quality/MediaQualityContract.java
+++ b/media/java/android/media/quality/MediaQualityContract.java
@@ -23,7 +23,6 @@
 /**
  * The contract between the media quality service and applications. Contains definitions for the
  * commonly used parameter names.
- * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 public class MediaQualityContract {
@@ -42,9 +41,8 @@
 
     /**
      * Parameters picture quality.
-     * @hide
      */
-    public static final class PictureQuality implements BaseParameters {
+    public static final class PictureQuality {
         /**
          * The brightness.
          *
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 4d4526c..28fe9b6 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -20,6 +20,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.media.tv.flags.Flags;
@@ -37,7 +38,6 @@
 /**
  * Central system API to the overall media quality, which arbitrates interaction between
  * applications and media quality service.
- * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 @SystemService(Context.MEDIA_QUALITY_SERVICE)
@@ -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
@@ -162,7 +180,6 @@
 
     /**
      * Registers a {@link PictureProfileCallback}.
-     * @hide
      */
     public void registerPictureProfileCallback(
             @NonNull @CallbackExecutor Executor executor,
@@ -176,7 +193,6 @@
 
     /**
      * Unregisters the existing {@link PictureProfileCallback}.
-     * @hide
      */
     public void unregisterPictureProfileCallback(@NonNull final PictureProfileCallback callback) {
         Preconditions.checkNotNull(callback);
@@ -198,7 +214,6 @@
      *
      * @return the corresponding picture profile if available; {@code null} if the name doesn't
      *         exist.
-     * @hide
      */
     @Nullable
     public PictureProfile getPictureProfile(
@@ -214,8 +229,9 @@
     /**
      * Gets profiles that available to the given package.
      *
-     * @hide @SystemApi
+     * @hide
      */
+    @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public List<PictureProfile> getPictureProfilesByPackage(@NonNull String packageName) {
@@ -242,8 +258,9 @@
      * Gets all package names whose picture profiles are available.
      *
      * @see #getPictureProfilesByPackage(String)
-     * @hide @SystemApi
+     * @hide
      */
+    @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public List<String> getPictureProfilePackageNames() {
@@ -258,14 +275,12 @@
     /**
      * Creates a picture profile and store it in the system.
      *
-     * @return the stored profile with an assigned profile ID. {@code null} if it's not created
-     * successfully.
-     * @hide
+     * <p>If the profile is created successfully,
+     * {@link PictureProfileCallback#onPictureProfileAdded(String, PictureProfile)} is invoked.
      */
-    @Nullable
-    public PictureProfile createPictureProfile(@NonNull PictureProfile pp) {
+    public void createPictureProfile(@NonNull PictureProfile pp) {
         try {
-            return mService.createPictureProfile(pp);
+            mService.createPictureProfile(pp);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -274,7 +289,6 @@
 
     /**
      * Updates an existing picture profile and store it in the system.
-     * @hide
      */
     public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) {
         try {
@@ -287,7 +301,6 @@
 
     /**
      * Removes a picture profile from the system.
-     * @hide
      */
     public void removePictureProfile(@NonNull String profileId) {
         try {
@@ -331,14 +344,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 +365,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 +379,7 @@
      * Gets profiles that available to the caller package
      * @hide
      */
+    @NonNull
     public List<SoundProfile> getAvailableSoundProfiles() {
         try {
             return mService.getAvailableSoundProfiles();
@@ -371,9 +389,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 +408,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 +425,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 +438,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) {
@@ -426,7 +448,6 @@
 
     /**
      * Gets capability information of the given parameters.
-     * @hide
      */
     @NonNull
     public List<ParamCapability> getParamCapabilities(@NonNull List<String> names) {
@@ -444,6 +465,7 @@
      * @see #removePictureProfile(String)
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     @NonNull
     public List<String> getPictureProfileAllowList() {
@@ -458,6 +480,7 @@
      * Sets the allowlist of packages that can create and removed picture profiles
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setPictureProfileAllowList(@NonNull List<String> packageNames) {
         try {
@@ -468,6 +491,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
      */
@@ -487,6 +540,7 @@
      * @param enabled {@code true} to enable, {@code false} to disable.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setAutoPictureQualityEnabled(boolean enabled) {
         try {
@@ -498,7 +552,6 @@
 
     /**
      * Returns {@code true} if auto picture quality is enabled; {@code false} otherwise.
-     * @hide
      */
     public boolean isAutoPictureQualityEnabled() {
         try {
@@ -515,6 +568,7 @@
      * @param enabled {@code true} to enable, {@code false} to disable.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
     public void setSuperResolutionEnabled(boolean enabled) {
         try {
@@ -526,7 +580,6 @@
 
     /**
      * Returns {@code true} if super resolution is enabled; {@code false} otherwise.
-     * @hide
      */
     public boolean isSuperResolutionEnabled() {
         try {
@@ -567,6 +620,7 @@
 
     /**
      * Registers a {@link AmbientBacklightCallback}.
+     * @hide
      */
     public void registerAmbientBacklightCallback(
             @NonNull @CallbackExecutor Executor executor,
@@ -580,6 +634,7 @@
 
     /**
      * Unregisters the existing {@link AmbientBacklightCallback}.
+     * @hide
      */
     public void unregisterAmbientBacklightCallback(
             @NonNull final AmbientBacklightCallback callback) {
@@ -600,6 +655,7 @@
      * Set the ambient backlight settings.
      *
      * @param settings The settings to use for the backlight detector.
+     * @hide
      */
     public void setAmbientBacklightSettings(
             @NonNull AmbientBacklightSettings settings) {
@@ -615,6 +671,7 @@
      * Enables or disables the ambient backlight detection.
      *
      * @param enabled {@code true} to enable, {@code false} to disable.
+     * @hide
      */
     public void setAmbientBacklightEnabled(boolean enabled) {
         try {
@@ -698,7 +755,7 @@
             return mCallback;
         }
 
-        public void postSoundProfileAdded(final long id, SoundProfile profile) {
+        public void postSoundProfileAdded(final String id, SoundProfile profile) {
 
             mExecutor.execute(new Runnable() {
                 @Override
@@ -708,7 +765,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() {
@@ -717,7 +774,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() {
@@ -725,6 +782,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 {
@@ -751,8 +826,7 @@
     }
 
     /**
-     * Callback used to monitor status of picture profiles.
-     * @hide
+     * Callback used to monitor status of picture profiles
      */
     public abstract static class PictureProfileCallback {
         /**
@@ -760,7 +834,6 @@
          *
          * @param profileId the ID of the profile.
          * @param profile the newly added profile.
-         * @hide
          */
         public void onPictureProfileAdded(
                 @NonNull String profileId, @NonNull PictureProfile profile) {
@@ -771,7 +844,6 @@
          *
          * @param profileId the ID of the profile.
          * @param profile the profile with updated info.
-         * @hide
          */
         public void onPictureProfileUpdated(
                 @NonNull String profileId, @NonNull PictureProfile profile) {
@@ -782,7 +854,6 @@
          *
          * @param profileId the ID of the profile.
          * @param profile the removed profile.
-         * @hide
          */
         public void onPictureProfileRemoved(
                 @NonNull String profileId, @NonNull PictureProfile profile) {
@@ -792,7 +863,6 @@
          * This is invoked when an issue has occurred.
          *
          * @param errorCode the error code
-         * @hide
          */
         public void onError(@PictureProfile.ErrorCode int errorCode) {
         }
@@ -801,12 +871,12 @@
          * 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) {
         }
     }
 
@@ -816,29 +886,64 @@
      */
     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) {
         }
     }
 
     /**
      * Callback used to monitor status of ambient backlight.
+     * @hide
      */
     public abstract static class AmbientBacklightCallback {
         /**
diff --git a/media/java/android/media/quality/ParamCapability.java b/media/java/android/media/quality/ParamCapability.java
index 0b698a9..ed11abd 100644
--- a/media/java/android/media/quality/ParamCapability.java
+++ b/media/java/android/media/quality/ParamCapability.java
@@ -31,7 +31,6 @@
 
 /**
  * Capability info of media quality parameters
- * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 public final class ParamCapability implements Parcelable {
diff --git a/media/java/android/media/quality/PictureProfile.java b/media/java/android/media/quality/PictureProfile.java
index 2be47dd..dcb4222 100644
--- a/media/java/android/media/quality/PictureProfile.java
+++ b/media/java/android/media/quality/PictureProfile.java
@@ -18,11 +18,12 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 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;
@@ -33,7 +34,6 @@
 
 /**
  * Profile for picture quality.
- * @hide
  */
 @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
 public final class PictureProfile implements Parcelable {
@@ -47,7 +47,7 @@
     @NonNull
     private final String mPackageName;
     @NonNull
-    private final Bundle mParams;
+    private final PersistableBundle mParams;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -59,14 +59,14 @@
     /**
      * System profile type.
      *
-     * <p>A profile of system type is managed by the system, and readable to the package define in
+     * <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 define in
+     * <p>A profile of application type is managed by the package returned by
      * {@link #getPackageName()}.
      */
     public static final int TYPE_APPLICATION = 2;
@@ -84,13 +84,11 @@
 
     /**
      * Error code for unknown errors.
-     * @hide
      */
     public static final int ERROR_UNKNOWN = 0;
 
     /**
      * Error code for missing necessary permission to handle the profiles.
-     * @hide
      */
     public static final int ERROR_NO_PERMISSION = 1;
 
@@ -99,13 +97,11 @@
      *
      * @see #getProfileType()
      * @see #getName()
-     * @hide
      */
     public static final int ERROR_DUPLICATE = 2;
 
     /**
      * Error code for invalid argument.
-     * @hide
      */
     public static final int ERROR_INVALID_ARGUMENT = 3;
 
@@ -114,7 +110,6 @@
      * list.
      *
      * @see MediaQualityManager#getPictureProfileAllowList()
-     * @hide
      */
     public static final int ERROR_NOT_ALLOWLISTED = 4;
 
@@ -125,7 +120,7 @@
         mName = in.readString();
         mInputId = in.readString();
         mPackageName = in.readString();
-        mParams = in.readBundle();
+        mParams = in.readPersistableBundle();
     }
 
     @Override
@@ -135,7 +130,7 @@
         dest.writeString(mName);
         dest.writeString(mInputId);
         dest.writeString(mPackageName);
-        dest.writeBundle(mParams);
+        dest.writePersistableBundle(mParams);
     }
 
     @Override
@@ -168,7 +163,7 @@
             @NonNull String name,
             @Nullable String inputId,
             @NonNull String packageName,
-            @NonNull Bundle params) {
+            @NonNull PersistableBundle params) {
         this.mId = id;
         this.mType = type;
         this.mName = name;
@@ -251,13 +246,12 @@
      * {@link MediaQualityContract.PictureQuality}.
      */
     @NonNull
-    public Bundle getParameters() {
-        return new Bundle(mParams);
+    public PersistableBundle getParameters() {
+        return new PersistableBundle(mParams);
     }
 
     /**
      * A builder for {@link PictureProfile}.
-     * @hide
      */
     public static final class Builder {
         @Nullable
@@ -270,7 +264,7 @@
         @NonNull
         private String mPackageName;
         @NonNull
-        private Bundle mParams;
+        private PersistableBundle mParams;
 
         /**
          * Creates a new Builder.
@@ -291,8 +285,6 @@
             mParams = p.getParameters();
         }
 
-        /* @hide using by MediaQualityService */
-
         /**
          * Only used by system to assign the ID.
          * @hide
@@ -306,8 +298,9 @@
         /**
          * Sets profile type.
          *
-         * @hide @SystemApi
+         * @hide
          */
+        @SystemApi
         @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
         @NonNull
         public Builder setProfileType(@ProfileType int value) {
@@ -320,8 +313,9 @@
          *
          * @see PictureProfile#getInputId()
          *
-         * @hide @SystemApi
+         * @hide
          */
+        @SystemApi
         @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
         @NonNull
         public Builder setInputId(@NonNull String value) {
@@ -334,8 +328,9 @@
          *
          * @see PictureProfile#getPackageName()
          *
-         * @hide @SystemApi
+         * @hide
          */
+        @SystemApi
         @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
         @NonNull
         public Builder setPackageName(@NonNull String value) {
@@ -349,8 +344,8 @@
          * @see PictureProfile#getParameters()
          */
         @NonNull
-        public Builder setParameters(@NonNull Bundle params) {
-            mParams = new Bundle(params);
+        public Builder setParameters(@NonNull PersistableBundle params) {
+            mParams = new PersistableBundle(params);
             return this;
         }
 
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/TvInputServiceExtensionManager.java b/media/java/android/media/tv/TvInputServiceExtensionManager.java
index 9442726..b876bcf 100644
--- a/media/java/android/media/tv/TvInputServiceExtensionManager.java
+++ b/media/java/android/media/tv/TvInputServiceExtensionManager.java
@@ -194,96 +194,78 @@
     public static final String ISCAN_INTERFACE = SCAN_PACKAGE + "IScanInterface";
     /**
      * Interface that handles scan session and get/store related information.
-     * @hide
      */
     public static final String ISCAN_SESSION = SCAN_PACKAGE + "IScanSession";
     /**
-     * Interface that notifies changes related to scan session.
-     * @hide
+     * Interface that notifies changes related to a scan session.
      */
     public static final String ISCAN_LISTENER = SCAN_PACKAGE + "IScanListener";
     /**
      * Interface for setting HDPlus information.
-     * @hide
      */
     public static final String IHDPLUS_INFO = SCAN_PACKAGE + "IHDPlusInfo";
     /**
      * Interface for handling operator detection for scanning.
-     * @hide
      */
     public static final String IOPERATOR_DETECTION = SCAN_PACKAGE + "IOperatorDetection";
     /**
-     * Interface for changes related to operator detection searches.
-     * @hide
+     * Interface for notifying changes related to operator detection searches.
      */
     public static final String IOPERATOR_DETECTION_LISTENER = SCAN_PACKAGE
             + "IOperatorDetectionListener";
     /**
      * Interface for handling region channel list for scanning.
-     * @hide
      */
     public static final String IREGION_CHANNEL_LIST = SCAN_PACKAGE + "IRegionChannelList";
     /**
-     * Interface for changes related to changes in region channel list search.
-     * @hide
+     * Interface for notifying changes related to changes in region channel list search.
      */
     public static final String IREGION_CHANNEL_LIST_LISTENER = SCAN_PACKAGE
             + "IRegionChannelListListener";
     /**
      * Interface for handling target region information.
-     * @hide
      */
     public static final String ITARGET_REGION = SCAN_PACKAGE + "ITargetRegion";
     /**
-     * Interface for changes related to target regions during scanning.
-     * @hide
+     * Interface for detecting changes related to target regions.
      */
     public static final String ITARGET_REGION_LISTENER = SCAN_PACKAGE + "ITargetRegionListener";
     /**
-     * Interface for handling LCN conflict groups.
-     * @hide
+     * Interface for handling logical channel number conflict groups.
      */
     public static final String ILCN_CONFLICT = SCAN_PACKAGE + "ILcnConflict";
     /**
-     * Interface for detecting LCN conflicts during scanning.
-     * @hide
+     * Interface for notifying changes in handling logical channel number conflicts.
      */
     public static final String ILCN_CONFLICT_LISTENER = SCAN_PACKAGE + "ILcnConflictListener";
     /**
-     * Interface for handling LCN V2 channel list information.
-     * @hide
+     * Interface for handling the updated standard for assigning logical channel numbers.
      */
     public static final String ILCNV2_CHANNEL_LIST = SCAN_PACKAGE + "ILcnV2ChannelList";
     /**
-     * Interface for detecting LCN V2 channel list during scanning.
-     * @hide
+     * Interface for notifying changes in assigning logical channel numbers with updated standard.
      */
     public static final String ILCNV2_CHANNEL_LIST_LISTENER = SCAN_PACKAGE
             + "ILcnV2ChannelListListener";
     /**
      * Interface for handling favorite network related information.
-     * @hide
      */
     public static final String IFAVORITE_NETWORK = SCAN_PACKAGE + "IFavoriteNetwork";
     /**
-     * Interface for detecting favorite network during scanning.
-     * @hide
+     * Interface for notifying changes favorite network during scanning.
      */
     public static final String IFAVORITE_NETWORK_LISTENER = SCAN_PACKAGE
             + "IFavoriteNetworkListener";
     /**
-     * Interface for handling Turksat channel update system service.
-     * @hide
+     * Interface for handling Turksat(TKGS) channel update system service.
      */
     public static final String ITKGS_INFO = SCAN_PACKAGE + "ITkgsInfo";
     /**
-     * Interface for changes related to TKGS information.
-     * @hide
+     * Interface for notifying changes related to Turksat(TKGS) information.
      */
     public static final String ITKGS_INFO_LISTENER = SCAN_PACKAGE + "ITkgsInfoListener";
     /**
      * Interface for satellite search related to low noise block downconverter.
-     * @hide
      */
     public static final String ISCAN_SAT_SEARCH = SCAN_PACKAGE + "IScanSatSearch";
     /**
@@ -295,113 +277,94 @@
      */
     public static final String ICAM_APP_INFO_SERVICE = CAM_PACKAGE + "ICamAppInfoService";
     /**
-     * Interface for changes on conditional access module app related information.
-     * @hide
+     * Interface for notifying changes on conditional access module app related information.
      */
     public static final String ICAM_APP_INFO_LISTENER = CAM_PACKAGE + "ICamAppInfoListener";
     /**
      * Interface for handling conditional access module related information.
-     * @hide
      */
     public static final String ICAM_MONITORING_SERVICE = CAM_PACKAGE + "ICamMonitoringService";
     /**
-     * Interface for changes on conditional access module related information.
-     * @hide
+     * Interface for notifying changes on conditional access module related information.
      */
     public static final String ICAM_INFO_LISTENER = CAM_PACKAGE + "ICamInfoListener";
     /**
-     * Interface for handling control of CI+ operations.
-     * @hide
+     * Interface for handling control of common interface plus operations.
      */
     public static final String ICI_OPERATOR_INTERFACE = CAM_PACKAGE + "ICiOperatorInterface";
     /**
-     * Interfaces for changes on CI+ operations.
-     * @hide
+     * Interfaces for notifying changes on common interface plus operations.
      */
     public static final String ICI_OPERATOR_LISTENER = CAM_PACKAGE + "ICiOperatorListener";
     /**
      * Interface for handling conditional access module profile related information.
-     * @hide
      */
     public static final String ICAM_PROFILE_INTERFACE = CAM_PACKAGE + "ICamProfileInterface";
     /**
-     * Interface for handling conditional access module DRM related information.
-     * @hide
+     * Interface for handling conditional access module digital rights management (DRM)
+     * related information.
      */
     public static final String ICONTENT_CONTROL_SERVICE = CAM_PACKAGE + "IContentControlService";
     /**
-     * Interface for changes on DRM.
-     * @hide
+     * Interface for notifying changes on digital rights management (DRM).
      */
     public static final String ICAM_DRM_INFO_LISTENER = CAM_PACKAGE + "ICamDrmInfoListener";
     /**
      * Interface for handling conditional access module pin related information.
-     * @hide
      */
     public static final String ICAM_PIN_SERVICE = CAM_PACKAGE + "ICamPinService";
     /**
-     * Interface for changes on conditional access module pin capability.
-     * @hide
+     * Interface for notifying changes on conditional access module pin capability.
      */
     public static final String ICAM_PIN_CAPABILITY_LISTENER = CAM_PACKAGE
             + "ICamPinCapabilityListener";
     /**
-     * Interface for changes on conditional access module pin status.
-     * @hide
+     * Interface for notifying changes on conditional access module pin status.
      */
     public static final String ICAM_PIN_STATUS_LISTENER = CAM_PACKAGE + "ICamPinStatusListener";
     /**
      * Interface for handling conditional access module host control service.
-     * @hide
      */
     public static final String ICAM_HOST_CONTROL_SERVICE = CAM_PACKAGE + "ICamHostControlService";
     /**
      * Interface for handling conditional access module ask release reply.
-     * @hide
      */
     public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = CAM_PACKAGE
             + "ICamHostControlAskReleaseReplyCallback";
     /**
-     * Interface for changes on conditional access module host control service.
-     * @hide
+     * Interface for notifying changes on conditional access module host control service.
      */
     public static final String ICAM_HOST_CONTROL_INFO_LISTENER = CAM_PACKAGE
             + "ICamHostControlInfoListener";
     /**
      * Interface for handling conditional access module host control service tune_quietly_flag.
-     * @hide
      */
     public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = CAM_PACKAGE
             + "ICamHostControlTuneQuietlyFlag";
     /**
-     * Interface for changes on conditional access module host control service tune_quietly_flag.
-     * @hide
+     * Interface for notifying changes on conditional access module host control service
+     * tune_quietly_flag.
      */
     public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = CAM_PACKAGE
             + "ICamHostControlTuneQuietlyFlagListener";
     /**
-     * Interface for handling conditional access module multi media interface.
-     * @hide
+     * Interface for handling conditional access module multi-media interface.
      */
     public static final String IMMI_INTERFACE = CAM_PACKAGE + "IMmiInterface";
     /**
-     * Interface for controlling conditional access module multi media session.
-     * @hide
+     * Interface for controlling conditional access module multi-media session.
      */
     public static final String IMMI_SESSION = CAM_PACKAGE + "IMmiSession";
     /**
-     * Interface for changes on conditional access module multi media session status.
-     * @hide
+     * Interface for notifying changes on conditional access module multi-media session status.
      */
     public static final String IMMI_STATUS_CALLBACK = CAM_PACKAGE + "IMmiStatusCallback";
     /**
-     * Interface for changes on conditional access app info related to entering menu.
-     * @hide
+     * Interface for notifying changes on conditional access app info related to entering menu.
      */
     public static final String IENTER_MENU_ERROR_CALLBACK = CAM_PACKAGE + "IEnterMenuErrorCallback";
     /**
-     * Interface for handling RRT downloadable rating data.
-     * @hide
+     * Interface for handling Region Rating Table downloadable rating data.
      */
     public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = RATING_PACKAGE
             + "IDownloadableRatingTableMonitor";
@@ -410,64 +373,54 @@
      */
     public static final String IRATING_INTERFACE = RATING_PACKAGE + "IRatingInterface";
     /**
-     * Interface for handling PMT rating related information.
-     * @hide
+     * Interface for handling Program Map Table rating related information.
      */
     public static final String IPMT_RATING_INTERFACE = RATING_PACKAGE + "IPmtRatingInterface";
     /**
-     * Interface for changes on PMT rating related information.
-     * @hide
+     * Interface for notifying changes on Program Map Table rating related information.
      */
     public static final String IPMT_RATING_LISTENER = RATING_PACKAGE + "IPmtRatingListener";
     /**
-     * Interface for handling IVBI rating related information.
-     * @hide
+     * Interface for handling Vertical Blanking Interval rating related information.
      */
     public static final String IVBI_RATING_INTERFACE = RATING_PACKAGE + "IVbiRatingInterface";
     /**
-     * Interface for changes on IVBI rating related information.
-     * @hide
+     * Interface for notifying changes on Vertical Blanking Interval rating related information.
      */
     public static final String IVBI_RATING_LISTENER = RATING_PACKAGE + "IVbiRatingListener";
     /**
      * Interface for handling program rating related information.
-     * @hide
      */
     public static final String IPROGRAM_INFO = RATING_PACKAGE + "IProgramInfo";
     /**
-     * Interface for changes on program rating related information.
-     * @hide
+     * Interface for notifying changes on program rating related information.
      */
     public static final String IPROGRAM_INFO_LISTENER = RATING_PACKAGE + "IProgramInfoListener";
     /**
      * Interface for getting broadcast time related information.
      */
-    public static final String IBROADCAST_TIME = TIME_PACKAGE + "BroadcastTime";
+    public static final String IBROADCAST_TIME = TIME_PACKAGE + "IBroadcastTime";
     /**
      * Interface for handling data service signal information on teletext.
      */
     public static final String IDATA_SERVICE_SIGNAL_INFO = TELETEXT_PACKAGE
             + "IDataServiceSignalInfo";
     /**
-     * Interface for changes on data service signal information on teletext.
-     * @hide
+     * Interface for notifying changes on data service signal information on teletext.
      */
     public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = TELETEXT_PACKAGE
             + "IDataServiceSignalInfoListener";
     /**
      * Interface for handling teletext page information.
-     * @hide
      */
     public static final String ITELETEXT_PAGE_SUB_CODE = TELETEXT_PACKAGE + "ITeletextPageSubCode";
     /**
      * Interface for handling scan background service update.
-     * @hide
      */
     public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = SCAN_BSU_PACKAGE
             + "IScanBackgroundServiceUpdate";
     /**
-     * Interface for changes on background service update
-     * @hide
+     * Interface for notifying changes on background service update
      */
     public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = SCAN_BSU_PACKAGE
             + "IScanBackgroundServiceUpdateListener";
@@ -484,98 +437,82 @@
      */
     public static final String IHDMI_SIGNAL_INTERFACE = SIGNAL_PACKAGE + "IHdmiSignalInterface";
     /**
-     * Interfaces for changes on HDMI signal information update.
-     * @hide
+     * Interfaces for notifying changes on HDMI signal information update.
      */
     public static final String IHDMI_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
             + "IHdmiSignalInfoListener";
     /**
      * Interfaces for handling audio signal information update.
-     * @hide
      */
     public static final String IAUDIO_SIGNAL_INFO = SIGNAL_PACKAGE + "IAudioSignalInfo";
     /**
      * Interfaces for handling analog audio signal information update.
-     * @hide
      */
     public static final String IANALOG_AUDIO_INFO = SIGNAL_PACKAGE + "IAnalogAudioInfo";
     /**
-     * Interfaces for change on audio signal information update.
-     * @hide
+     * Interfaces for notifying changes on audio signal information update.
      */
     public static final String IAUDIO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
             + "IAudioSignalInfoListener";
     /**
      * Interfaces for handling video signal information update.
-     * @hide
      */
     public static final String IVIDEO_SIGNAL_INFO = SIGNAL_PACKAGE + "IVideoSignalInfo";
     /**
-     * Interfaces for changes on video signal information update.
-     * @hide
+     * Interfaces for notifying changes on video signal information update.
      */
     public static final String IVIDEO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
             + "IVideoSignalInfoListener";
     /**
      * Interfaces for handling service database updates.
-     * @hide
      */
     public static final String ISERVICE_LIST_EDIT = SERVICE_DATABASE_PACKAGE + "IServiceListEdit";
     /**
-     * Interfaces for changes on service database updates.
+     * Interfaces for notifying changes on service database updates.
      */
     public static final String ISERVICE_LIST_EDIT_LISTENER = SERVICE_DATABASE_PACKAGE
             + "IServiceListEditListener";
     /**
      * Interfaces for getting service database related information.
-     * @hide
      */
     public static final String ISERVICE_LIST = SERVICE_DATABASE_PACKAGE + "IServiceList";
     /**
      * Interfaces for transferring service database related information.
-     * @hide
      */
     public static final String ISERVICE_LIST_TRANSFER_INTERFACE = SERVICE_DATABASE_PACKAGE
             + "IServiceListTransferInterface";
     /**
      * Interfaces for exporting service database session.
-     * @hide
      */
     public static final String ISERVICE_LIST_EXPORT_SESSION = SERVICE_DATABASE_PACKAGE
             + "IServiceListExportSession";
     /**
-     * Interfaces for changes on exporting service database session.
-     * @hide
+     * Interfaces for notifying changes on exporting service database session.
      */
     public static final String ISERVICE_LIST_EXPORT_LISTENER = SERVICE_DATABASE_PACKAGE
             + "IServiceListExportListener";
     /**
      * Interfaces for importing service database session.
-     * @hide
      */
     public static final String ISERVICE_LIST_IMPORT_SESSION = SERVICE_DATABASE_PACKAGE
             + "IServiceListImportSession";
     /**
-     * Interfaces for changes on importing service database session.
-     * @hide
+     * Interfaces for notifying changes on importing service database session.
      */
     public static final String ISERVICE_LIST_IMPORT_LISTENER = SERVICE_DATABASE_PACKAGE
             + "IServiceListImportListener";
     /**
      * Interfaces for setting channel list resources.
-     * @hide
      */
     public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = SERVICE_DATABASE_PACKAGE
             + "IServiceListSetChannelListSession";
     /**
-     * Interfaces for changes on setting channel list resources.
-     * @hide
+     * Interfaces for notifying changes on setting channel list resources.
      */
     public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = SERVICE_DATABASE_PACKAGE
             + "IServiceListSetChannelListListener";
     /**
      * Interfaces for transferring channel list resources.
-     * @hide
      */
     public static final String ICHANNEL_LIST_TRANSFER = SERVICE_DATABASE_PACKAGE
             + "IChannelListTransfer";
@@ -584,14 +521,12 @@
      */
     public static final String IRECORDED_CONTENTS = PVR_PACKAGE + "IRecordedContents";
     /**
-     * Interfaces for changes on deleting record contents.
-     * @hide
+     * Interfaces for notifying changes on deleting record contents.
      */
     public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE
             + "IDeleteRecordedContentsCallback";
     /**
-     * Interfaces for changes on getting record contents.
-     * @hide
+     * Interfaces for notifying changes on getting record contents.
      */
     public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE
             + "IGetInfoRecordedContentsCallback";
@@ -600,61 +535,51 @@
      */
     public static final String IEVENT_MONITOR = EVENT_PACKAGE + "IEventMonitor";
     /**
-     * Interfaces for changes on present event information.
-     * @hide
+     * Interfaces for notifying changes on present event information.
      */
     public static final String IEVENT_MONITOR_LISTENER = EVENT_PACKAGE + "IEventMonitorListener";
     /**
      * Interfaces for handling download event information.
-     * @hide
      */
     public static final String IEVENT_DOWNLOAD = EVENT_PACKAGE + "IEventDownload";
     /**
-     * Interfaces for changes on downloading event information.
-     * @hide
+     * Interfaces for notifying changes on downloading event information.
      */
     public static final String IEVENT_DOWNLOAD_LISTENER = EVENT_PACKAGE + "IEventDownloadListener";
     /**
-     * Interfaces for handling download event information for DVB and DTMB.
-     * @hide
+     * Interfaces for handling download event information for Digital Video Broadcast
+     * and Digital Terrestrial Multimedia Broadcast.
      */
     public static final String IEVENT_DOWNLOAD_SESSION = EVENT_PACKAGE + "IEventDownloadSession";
     /**
      * Interfaces for handling analog color system.
-     * @hide
      */
     public static final String IANALOG_ATTRIBUTE_INTERFACE = ANALOG_PACKAGE
             + "IAnalogAttributeInterface";
     /**
      * Interfaces for monitoring channel tuned information.
-     * @hide
      */
     public static final String ICHANNEL_TUNED_INTERFACE = TUNE_PACKAGE + "IChannelTunedInterface";
     /**
-     * Interfaces for changes on channel tuned information.
-     * @hide
+     * Interfaces for notifying changes on channel tuned information.
      */
     public static final String ICHANNEL_TUNED_LISTENER = TUNE_PACKAGE + "IChannelTunedListener";
     /**
      * Interfaces for handling tuner frontend signal info.
-     * @hide
      */
     public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = SIGNAL_PACKAGE
             + "ITunerFrontendSignalInfoInterface";
     /**
-     * Interfaces for changes on tuner frontend signal info.
-     * @hide
+     * Interfaces for notifying changes on tuner frontend signal info.
      */
     public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE
             + "ITunerFrontendSignalInfoListener";
     /**
      * Interfaces for handling mux tune operations.
-     * @hide
      */
     public static final String IMUX_TUNE_SESSION = TUNE_PACKAGE + "IMuxTuneSession";
     /**
      * Interfaces for initing mux tune session.
-     * @hide
      */
     public static final String IMUX_TUNE = TUNE_PACKAGE + "IMuxTune";
 
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/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl
new file mode 100644
index 0000000..62f1511
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.pvr;
+
+/**
+ * @hide
+ */
+oneway interface IDeleteRecordedContentsCallback {
+    void onRecordedContentsDeleted(in String[] contentUri, in int[] result);
+}
diff --git a/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl
new file mode 100644
index 0000000..64f8fc2
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.pvr;
+
+/**
+ * @hide
+ */
+interface IGetInfoRecordedContentsCallback {
+    void onRecordedContentsGetInfo(int result);
+}
diff --git a/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl
new file mode 100644
index 0000000..74a15b8
--- /dev/null
+++ b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.pvr;
+
+import android.media.tv.extension.pvr.IDeleteRecordedContentsCallback;
+import android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback;
+
+
+/**
+ * @hide
+ */
+interface IRecordedContents {
+    // Delete recorded contents by URIs
+    // using callback to notify the result or any errors during the deletion process.
+    void deleteRecordedContents(in String[] contentUri,
+        in IDeleteRecordedContentsCallback callback);
+    // Get the channel lock status for recorded content identified by the URI provided in sync way.
+    int getRecordedContentsLockInfoSync(String contentUri);
+    // Get the channel lock status for recorded content identified by the URI provided in async way.
+    void getRecordedContentsLockInfoAsync(String contentUri,
+        in IGetInfoRecordedContentsCallback callback);
+}
diff --git a/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
new file mode 100644
index 0000000..bf1a385
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl
@@ -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 android.media.tv.extension.rating;
+
+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/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
new file mode 100644
index 0000000..d88ae94
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * @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/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
new file mode 100644
index 0000000..6777cd3
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IProgramRatingInfoListener {
+    void onProgramInfoChanged(String sessionToken,in Bundle changedProgramInfo);
+}
diff --git a/media/java/android/media/tv/extension/rating/IRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl
new file mode 100644
index 0000000..d68fe76
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IRatingInterface.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.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/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
new file mode 100644
index 0000000..36d523f
--- /dev/null
+++ b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+oneway interface IVbiRatingListener {
+    void onVbiRatingChanged(String sessionToken, String newTvContentRating);
+}
diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
new file mode 100644
index 0000000..ff78aa4
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.IFavoriteNetworkListener;
+import android.os.Bundle;
+
+/**
+ * Country: Norway
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ * (Operator: RiksTV)
+ *
+ * @hide
+ */
+interface IFavoriteNetwork {
+    // Get the favorite network information,If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getFavoriteNetworks();
+    // Select and set one of two or more favorite networks detected by the service scan.
+    int setFavoriteNetwork(in Bundle favoriteNetworkSettings);
+    // Set the listener to be invoked when two or more favorite networks are detected.
+    int setListener(in IFavoriteNetworkListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
new file mode 100644
index 0000000..6994224
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IFavoriteNetworkListener {
+    void onDetectFavoriteNetwork(in Bundle detectFavoriteNetworks);
+}
diff --git a/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
new file mode 100644
index 0000000..cdf6e23
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.scan;
+
+/**
+ * @hide
+ */
+interface IHDPlusInfo {
+    // Specifying a HDPlusInfo and start a network scan.
+    int setHDPlusInfo(String isBlindScanContinue, String isHDMode);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnConflict.aidl b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
new file mode 100644
index 0000000..5dff39e
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.ILcnConflictListener;
+import android.os.Bundle;
+
+/**
+ * Country: Italy, France
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ILcnConflict {
+    // Get the LCN conflict groups information, If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getLcnConflictGroups();
+    // Resolve LCN conflicts caused by service scans.
+    int resolveLcnConflict(in Bundle[] lcnConflictSettings);
+    // Set the listener to be invoked the LCN conflict event.
+    int setListener(in ILcnConflictListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
new file mode 100644
index 0000000..6bbbeb8
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnConflictListener {
+    void onDetectLcnConflict(in Bundle detectLcnConflicts);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
new file mode 100644
index 0000000..f9a9d34
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.ILcnV2ChannelListListener;
+import android.os.Bundle;
+
+/**
+ * Country: (NorDig etc.)
+ * Broadcast Type: BROADCAST_TYPE_DVB_T, BROADCAST_TYPE_DVB_C
+ *
+ * @hide
+ */
+interface ILcnV2ChannelList {
+    // Get the LCN V2 channel list information. If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getLcnV2ChannelLists();
+    // Select and set one of two or more LCN V2 channel list detected by the service scan.
+    int setLcnV2ChannelList(in Bundle lcnV2ChannelListSettings);
+    // Set the listener to be invoked when two or more LCN V2 channel list are detected.
+    int setListener(in ILcnV2ChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
new file mode 100644
index 0000000..cbdb83c
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ILcnV2ChannelListListener {
+    void onDetectLcnV2ChannelList(in Bundle detectLcnV2ChannelList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
new file mode 100644
index 0000000..770f866
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.IOperatorDetectionListener;
+import android.os.Bundle;
+
+/**
+ * Country: Any
+ * Broadcast Type: BROADCAST_TYPE_DVB_S
+ * (Operator: M7)
+ *
+ * @hide
+ */
+interface IOperatorDetection {
+    // Set the operator selected info for scanning.
+    int setOperatorDetection(in Bundle operatorSelected);
+    // Set the listener to be invoked when one or more operator detection has been detected by
+    // operator detection searches.
+    int setListener(in IOperatorDetectionListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
new file mode 100644
index 0000000..7dcd461
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl
@@ -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 android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+oneway interface IOperatorDetectionListener {
+    void onDetectOperatorDetectionList(in Bundle[] detectOperatorDetectionList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
new file mode 100644
index 0000000..fe755f8
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.IRegionChannelListListener;
+
+/**
+ * @hide
+ */
+interface IRegionChannelList {
+    // Set the region channel list for scanning.
+    int setRegionChannelList(String regionChannelList);
+    // Set the listener to be invoked when one or more region channel list has been detected by
+    // region channel list searches.
+    int setListener(in IRegionChannelListListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
new file mode 100644
index 0000000..06b0eb5
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.scan;
+
+/**
+ * @hide
+ */
+oneway interface IRegionChannelListListener {
+    void onDetectRegionChannelList(in String[] detectRegionChannelList);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanInterface.aidl b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
new file mode 100644
index 0000000..b44d1d2
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanInterface.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.IScanListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanInterface {
+    IBinder createSession(int broadcastType, String countryCode, String operator,
+        in IScanListener listener);
+    Bundle getParameters(int broadcastType, String countryCode, String operator,
+        in Bundle params);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanListener.aidl b/media/java/android/media/tv/extension/scan/IScanListener.aidl
new file mode 100644
index 0000000..2c4807f
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanListener.aidl
@@ -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 android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IScanListener {
+    // notify events during scan.
+    void onEvent(in Bundle eventArgs);
+    // notify the scan progress.
+    void onScanProgress(String scanProgress, in Bundle scanProgressInfo);
+    // notify the scan completion.
+    void onScanCompleted(int scanResult);
+    // notify that the temporaily held channel list is stored.
+    void onStoreCompleted(int storeResult);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
new file mode 100644
index 0000000..b8074fc
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+/**
+ * For satellite search function.
+ * @hide
+ */
+interface IScanSatSearch {
+    // Set currecnt LNB as customized LNB, default LNB is universal LNB
+    int setCustomizedLnb(String customizedLnb);
+}
diff --git a/media/java/android/media/tv/extension/scan/IScanSession.aidl b/media/java/android/media/tv/extension/scan/IScanSession.aidl
new file mode 100644
index 0000000..d42eca1
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/IScanSession.aidl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IScanSession {
+    // Start a service scan.
+    int startScan(int broadcastType, String countryCode, String operator, in int[] frequency,
+        String scanType, String languageCode);
+    // Reset the scan information held in TIS.
+    int resetScan();
+    // Cancel scan.
+    int cancelScan();
+
+    // Get available interface for created ScanExtension interface.
+    String[] getAvailableExtensionInterfaceNames();
+    // Get extension interface for Scan.
+    IBinder getExtensionInterface(String name);
+
+    // Clear the results of the service scan from the service database.
+    int clearServiceList(in Bundle optionalClearParams);
+    // Store the results of the service scan from the service database.
+    int storeServiceList();
+    // Get a service information specified by the service information ID.
+    Bundle getServiceInfo(String serviceInfoId, in String[] keys);
+    // Get a service information ID list.
+    String[] getServiceInfoIdList();
+    // Get a list of service info by the filter.
+    Bundle getServiceInfoList(in Bundle filterInfo, in String[] keys);
+    // Update the service information.
+    int updateServiceInfo(in Bundle serviceInfo);
+    // Updates the service information for the specified service information ID in array list.
+    int updateServiceInfoByList(in Bundle[] serviceInfo);
+
+    /* DVBI specific functions */
+    // Get all of the serviceLists, parsed from Local TV storage, Broadcast, USB file discovery.
+    Bundle getServiceLists();
+    // Users choose one serviceList from the serviceLists, and install the services.
+    int setServiceList(int serviceListRecId);
+    // Get all of the packageData, parsed from the selected serviceList XML.
+    Bundle getPackageData();
+    // Choose the package using package id and install the corresponding services.
+    int setPackage(String packageId);
+    // Get all of the countryRegionData, parsed from the selected serviceList XML.
+    Bundle getCountryRegionData();
+    // Choose the countryRegion using countryRegion id, and install the corresponding services.
+    int setCountryRegion(String regionId);
+    // Get all of the regionData, parsed from the selected serviceList XML.
+    Bundle getRegionData();
+    // Choose the region using the regionData id, and install the corresponding services.
+    int setRegion(String regionId);
+
+    // Get unique session token for the scan.
+    String getSessionToken();
+    // Release scan resource, the register listener will be released.
+    int release();
+}
diff --git a/media/java/android/media/tv/extension/scan/ITargetRegion.aidl b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
new file mode 100644
index 0000000..417e122
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.scan;
+
+import android.media.tv.extension.scan.ITargetRegionListener;
+
+import android.os.Bundle;
+
+/**
+ * Country: U.K.
+ * Broadcast Type: BROADCAST_TYPE_DVB_T
+ *
+ * @hide
+ */
+interface ITargetRegion {
+    // Get the target regions information. If there are no conflicts, the array of Bundle is empty.
+    Bundle[] getTargetRegions();
+    // Select and set one of two or more target region detected by the service scan.
+    int setTargetRegion(in Bundle targetRegionSettings);
+    // Set the listener to be invoked when two or more regions are detected.
+    int setListener(in ITargetRegionListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
new file mode 100644
index 0000000..9d6aa8e
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ITargetRegionListener {
+    void onDetectTargetRegion(in Bundle detectTargetRegions);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
new file mode 100644
index 0000000..f25952c
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.scan;
+
+import android.media.tv.extension.scan.ITkgsInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface ITkgsInfo {
+     int setPrefServiceList(String prefServiceList);
+     int setTkgsInfoListener(in ITkgsInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
new file mode 100644
index 0000000..e3dcf2d
--- /dev/null
+++ b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.scan;
+
+/**
+ * @hide
+ */
+oneway interface ITkgsInfoListener {
+    void onServiceList(in String[] serviceList);
+    void onTableVersionUpdate(int tableVersion);
+    void onUserMessage(String strMessage);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl
new file mode 100644
index 0000000..742191f
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IAnalogAudioInfo {
+    Bundle getAnalogAudioInfo(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl
new file mode 100644
index 0000000..4c953a0
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.signal;
+
+import android.media.tv.extension.signal.IAudioSignalInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IAudioSignalInfo {
+    // Get audio signal information.
+    Bundle getAudioSignalInfo(String sessionToken);
+    // Notify TIS whether user selects audio track via mts button on the remote control.
+    void notifyMtsSelectTrackFlag(boolean mtsFlag);
+    // Get the audio track id selected via mts.
+    String getMtsSelectedTrackId();
+    // Register a listener to receive the updated audio signal information.
+    void addAudioSignalInfoListener(String clientToken, in IAudioSignalInfoListener listener);
+    // Remove a listener for audio signal information update notifications.
+    void removeAudioSignalInfoListener(in IAudioSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl
new file mode 100644
index 0000000..adf239a
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IAudioSignalInfoListener {
+    void onAudioSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl
new file mode 100644
index 0000000..bd468b2
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.signal;
+
+/**
+ * @hide
+ */
+oneway interface IHdmiSignalInfoListener {
+    void onSignalInfoChanged(String sessionToken);
+    void onLowLatencyModeChanged(int enable);
+}
diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl
new file mode 100644
index 0000000..39625e3
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.signal;
+
+import android.media.tv.extension.signal.IHdmiSignalInfoListener;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+interface IHdmiSignalInterface {
+    // Register a listener for Hdmi Signal Info updates.
+    void addHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener);
+    // Remove a listener for Hdmi Signal Info update notifications.
+    void removeHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener);
+    // Obtain HdmiSignalInfo based on the inputId and sessionToken.
+    Bundle getHdmiSignalInfo(String sessionToken);
+    // Enable/disable low-latency decoding mode.
+    void setLowLatency(String sessionToken, int mode);
+    // Enable/disable force-VRR mode.
+    void setForceVrr(String sessionToken, int mode);
+}
diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl
new file mode 100644
index 0000000..7f05e70
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.extension.signal;
+
+import android.media.tv.extension.signal.ITunerFrontendSignalInfoListener;
+import android.os.Bundle;
+
+/**
+* @hide
+*/
+interface ITunerFrontendSignalInfoInterface {
+    Bundle getFrontendSignalInfo(String sessionToken);
+    void setFrontendSignalInfoListener(in ITunerFrontendSignalInfoListener listener);
+}
diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl
new file mode 100644
index 0000000..9c22a35
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.signal;
+
+/**
+* @hide
+*/
+oneway interface ITunerFrontendSignalInfoListener {
+    void onFrontendStatusChanged(int frontendStatus);
+}
diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl
new file mode 100644
index 0000000..b17142a
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.signal;
+
+import android.media.tv.extension.signal.IVideoSignalInfoListener;
+import android.os.Bundle;
+
+
+/**
+ * @hide
+ */
+interface IVideoSignalInfo {
+    void addVideoSignalInfoListener(String clientToken, in IVideoSignalInfoListener listener);
+    void removeVideoSignalInfoListener(in IVideoSignalInfoListener listener);
+    Bundle getVideoSignalInfo(String sessionToken);
+}
diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl
new file mode 100644
index 0000000..aafc192
--- /dev/null
+++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.signal;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IVideoSignalInfoListener {
+    void onVideoSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo);
+}
diff --git a/media/java/android/media/tv/extension/time/IBroadcastTime.aidl b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
new file mode 100644
index 0000000..123d00f
--- /dev/null
+++ b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.time;
+
+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/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d05ee55..a942300 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1362,13 +1362,26 @@
     return mp->setOutputDevice(device_id) == NO_ERROR;
 }
 
-static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray android_media_MediaPlayer_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL) {
-        return AUDIO_PORT_HANDLE_NONE;
+        return NULL;
     }
-    return mp->getRoutedDeviceId();
+    DeviceIdVector deviceIds;
+    // TODO: b/379161379 - Should we throw an exception if the result is not ok?
+    mp->getRoutedDeviceIds(deviceIds);
+    jintArray result;
+    result = env->NewIntArray(deviceIds.size());
+    if (result == NULL) {
+        return NULL;
+    }
+    jint* values = env->GetIntArrayElements(result, 0);
+    for (unsigned int i = 0; i < deviceIds.size(); i++) {
+        values[i++] = static_cast<jint>(deviceIds[i]);
+    }
+    env->ReleaseIntArrayElements(result, values, 0);
+    return result;
 }
 
 static void android_media_MediaPlayer_enableDeviceCallback(
@@ -1452,7 +1465,8 @@
 
     // AudioRouting
     {"native_setOutputDevice", "(I)Z",                          (void *)android_media_MediaPlayer_setOutputDevice},
-    {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaPlayer_getRoutedDeviceId},
+    {"native_getRoutedDeviceIds", "()[I",
+         (void *)android_media_MediaPlayer_getRoutedDeviceIds},
     {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaPlayer_enableDeviceCallback},
 };
 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 9a6d5d7..643fc8a 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -722,21 +722,31 @@
     return true;
 }
 
-static jint
-android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+static jintArray
+android_media_MediaRecorder_getRoutedDeviceIds(JNIEnv *env, jobject thiz)
 {
-    ALOGV("android_media_MediaRecorder_getRoutedDeviceId");
+    ALOGV("android_media_MediaRecorder_getRoutedDeviceIds");
 
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
     if (mr == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return AUDIO_PORT_HANDLE_NONE;
+        return NULL;
     }
 
-    audio_port_handle_t deviceId;
-    process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId),
-            "java/lang/RuntimeException", "getRoutedDeviceId failed.");
-    return (jint) deviceId;
+    DeviceIdVector deviceIds;
+    process_media_recorder_call(env, mr->getRoutedDeviceIds(deviceIds),
+            "java/lang/RuntimeException", "getRoutedDeviceIds failed.");
+    jintArray result;
+    result = env->NewIntArray(deviceIds.size());
+    if (result == NULL) {
+        return NULL;
+    }
+    jint* values = env->GetIntArrayElements(result, 0);
+    for (unsigned int i = 0; i < deviceIds.size(); i++) {
+        values[i++] = static_cast<jint>(deviceIds[i]);
+    }
+    env->ReleaseIntArrayElements(result, values, 0);
+    return result;
 }
 
 static void
@@ -880,7 +890,8 @@
     {"native_getMetrics",    "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics},
 
     {"native_setInputDevice", "(I)Z",                           (void *)android_media_MediaRecorder_setInputDevice},
-    {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaRecorder_getRoutedDeviceId},
+    {"native_getRoutedDeviceIds", "()[I",
+         (void *)android_media_MediaRecorder_getRoutedDeviceIds},
     {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaRecorder_enableDeviceCallback},
 
     {"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
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/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/current.txt b/nfc/api/current.txt
index 00812042..9a7a39f 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -81,11 +81,14 @@
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
     method public boolean isSecureNfcEnabled();
     method public boolean isSecureNfcSupported();
+    method @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public boolean isTagIntentAllowed();
+    method @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public boolean isTagIntentAppPreferenceSupported();
     method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled();
     method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity);
     method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setObserveModeEnabled(boolean);
     field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
+    field @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE = "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
     field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
     field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
     field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index c25f77b..15814ed 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -11,7 +11,6 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
     method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerNfcVendorNciCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
     method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener);
@@ -57,6 +56,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 +73,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 +92,15 @@
     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 onEeUpdated();
     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,7 @@
     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);
@@ -183,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..a08b55f 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -120,4 +120,6 @@
     boolean isTagPresent();
     List<Entry> getRoutingTableEntryList();
     void indicateDataMigration(boolean inProgress, String pkg);
+    int commitRouting();
+    boolean isTagIntentAllowed(in String pkg, in int Userid);
 }
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 fb793b0..e5eac0b 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -41,17 +41,19 @@
    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);
    void onRfFieldActivated(boolean isActivated);
    void onRfDiscoveryStarted(boolean isDiscoveryStarted);
    void onEeListenActivated(boolean isActivated);
+   void onEeUpdated();
    void onGetOemAppSearchIntent(in List<String> firstPackage, in ResultReceiver intentConsumer);
    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/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index c5d8191..056844f 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -49,6 +49,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.io.IOException;
@@ -2505,22 +2506,22 @@
     }
 
     /**
-     * Checks if the device supports Tag application preference.
+     * Checks if the device supports Tag Intent App Preference functionality.
+     *
+     * When supported, {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
+     * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if
+     * {@link isTagIntentAllowed} returns {@code false}.
      *
      * @return {@code true} if the device supports Tag application preference, {@code false}
      * otherwise
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
-     *
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
     public boolean isTagIntentAppPreferenceSupported() {
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
         return callServiceReturn(() ->  sService.isTagIntentAppPreferenceSupported(), false);
-
     }
 
    /**
@@ -2895,4 +2896,42 @@
         }
         return mNfcOemExtension;
     }
+
+    /**
+     * Activity action: Bring up the settings page that allows the user to enable or disable tag
+     * intent reception for apps.
+     *
+     * <p>This will direct user to the settings page shows a list that asks users whether
+     * they want to allow or disallow the package to start an activity when a tag is discovered.
+     *
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
+    public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE =
+            "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
+
+    /**
+     * Checks whether the user has disabled the calling app from receiving NFC tag intents.
+     *
+     * <p>This method checks whether the caller package name is either not present in the user
+     * disabled list or is explicitly allowed by the user.
+     *
+     * @return {@code true} if an app is either not present in the list or is added to the list
+     * with the flag set to {@code true}. Otherwise, it returns {@code false}.
+     * It also returns {@code true} if {@link isTagIntentAppPreferenceSupported} returns
+     * {@code false}.
+     *
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
+    public boolean isTagIntentAllowed() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        if (!isTagIntentAppPreferenceSupported()) {
+            return true;
+        }
+        return callServiceReturn(() ->  sService.isTagIntentAllowed(mContext.getPackageName(),
+                UserHandle.myUserId()), false);
+    }
 }
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 57ee981..9ed678f 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.
@@ -340,6 +367,15 @@
         void onEeListenActivated(boolean isActivated);
 
         /**
+        * Notifies that some NFCEE (NFC Execution Environment) has been updated.
+        *
+        * <p> This indicates that some applet has been installed/updated/removed in
+        * one of the NFCEE's.
+        * </p>
+        */
+        void onEeUpdated();
+
+        /**
          * Gets the intent to find the OEM package in the OEM App market. If the consumer returns
          * {@code null} or a timeout occurs, the intent from the first available package will be
          * used instead.
@@ -405,6 +441,19 @@
          * @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);
     }
 
 
@@ -605,12 +654,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));
     }
 
@@ -741,6 +790,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
@@ -778,6 +839,12 @@
         }
 
         @Override
+        public void onEeUpdated() throws RemoteException {
+            mCallbackMap.forEach((cb, ex) ->
+                    handleVoidCallback(null, (Object input) -> cb.onEeUpdated(), ex));
+        }
+
+        @Override
         public void onStateUpdated(int state) throws RemoteException {
             mCallbackMap.forEach((cb, ex) ->
                     handleVoidCallback(state, cb::onStateUpdated, ex));
@@ -799,13 +866,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 {
@@ -844,9 +911,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 {
@@ -925,6 +993,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) {
@@ -1035,8 +1112,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/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..ee287ab 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -173,3 +173,19 @@
     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"
+}
+
+flag {
+    name: "nfc_check_tag_intent_preference"
+    is_exported: true
+    namespace: "nfc"
+    description: "App can check its tag intent preference status"
+    bug: "335916336"
+}
diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
index fbf51fd..8c15b09 100644
--- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java
@@ -218,7 +218,7 @@
     @GuardedBy("sPackageWatchdogLock")
     private static PackageWatchdog sPackageWatchdog;
 
-    private final Object mLock = new Object();
+    private static final Object sLock = new Object();
     // System server context
     private final Context mContext;
     // Handler to run short running tasks
@@ -228,7 +228,7 @@
     // Contains (observer-name -> observer-handle) that have ever been registered from
     // previous boots. Observers with all packages expired are periodically pruned.
     // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
     // File containing the XML data of monitored packages /data/system/package-watchdog.xml
     private final AtomicFile mPolicyFile;
@@ -244,26 +244,26 @@
     private final Set<String> mPackagesExemptFromImpactLevelThreshold = new ArraySet<>();
 
     // The set of packages that have been synced with the ExplicitHealthCheckController
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private boolean mIsPackagesReady;
     // Flag to control whether explicit health checks are supported or not
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED;
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
     // SystemClock#uptimeMillis when we last executed #syncState
     // 0 if no prune is scheduled.
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private long mUptimeAtLastStateSync;
     // If true, sync explicit health check packages with the ExplicitHealthCheckController.
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private boolean mSyncRequired = false;
 
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private long mLastMitigation = -1000000;
 
     @FunctionalInterface
@@ -303,7 +303,11 @@
         sPackageWatchdog = this;
     }
 
-    /** Creates or gets singleton instance of PackageWatchdog. */
+    /**
+     * Creates or gets singleton instance of PackageWatchdog.
+     *
+     * @param context The system server context.
+     */
     public static  @NonNull PackageWatchdog getInstance(@NonNull Context context) {
         synchronized (sPackageWatchdogLock) {
             if (sPackageWatchdog == null) {
@@ -319,7 +323,7 @@
      * @hide
      */
     public void onPackagesReady() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             mIsPackagesReady = true;
             mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
                     packages -> onSupportedPackages(packages),
@@ -338,7 +342,7 @@
      * @hide
      */
     public void registerHealthObserver(PackageHealthObserver observer) {
-        synchronized (mLock) {
+        synchronized (sLock) {
             ObserverInternal internalObserver = mAllObservers.get(observer.getUniqueIdentifier());
             if (internalObserver != null) {
                 internalObserver.registeredObserver = observer;
@@ -405,7 +409,7 @@
         mLongTaskHandler.post(() -> {
             syncState("observing new packages");
 
-            synchronized (mLock) {
+            synchronized (sLock) {
                 ObserverInternal oldObserver = mAllObservers.get(observer.getUniqueIdentifier());
                 if (oldObserver == null) {
                     Slog.d(TAG, observer.getUniqueIdentifier() + " started monitoring health "
@@ -437,7 +441,7 @@
      */
     public void unregisterHealthObserver(PackageHealthObserver observer) {
         mLongTaskHandler.post(() -> {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 mAllObservers.remove(observer.getUniqueIdentifier());
             }
             syncState("unregistering observer: " + observer.getUniqueIdentifier());
@@ -458,7 +462,7 @@
             Slog.w(TAG, "Could not resolve a list of failing packages");
             return;
         }
-        synchronized (mLock) {
+        synchronized (sLock) {
             final long now = mSystemClock.uptimeMillis();
             if (Flags.recoverabilityDetection()) {
                 if (now >= mLastMitigation
@@ -469,7 +473,7 @@
             }
         }
         mLongTaskHandler.post(() -> {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 if (mAllObservers.isEmpty()) {
                     return;
                 }
@@ -569,7 +573,7 @@
                               int currentObserverImpact,
                               int mitigationCount) {
         if (allowMitigations(currentObserverImpact, versionedPackage)) {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 mLastMitigation = mSystemClock.uptimeMillis();
             }
             currentObserverToNotify.onExecuteHealthCheckMitigation(versionedPackage, failureReason,
@@ -599,7 +603,7 @@
      */
     @SuppressWarnings("GuardedBy")
     public void noteBoot() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             // if boot count has reached threshold, start mitigation.
             // We wait until threshold number of restarts only for the first time. Perform
             // mitigations for every restart after that.
@@ -652,7 +656,7 @@
     // This currently adds about 7ms extra to shutdown thread
     /** @hide Writes the package information to file during shutdown. */
     public void writeNow() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             // Must only run synchronous tasks as this runs on the ShutdownThread and no other
             // thread is guaranteed to run during shutdown.
             if (!mAllObservers.isEmpty()) {
@@ -671,7 +675,7 @@
      * passed and the health check service is stopped.
      */
     private void setExplicitHealthCheckEnabled(boolean enabled) {
-        synchronized (mLock) {
+        synchronized (sLock) {
             mIsHealthCheckEnabled = enabled;
             mHealthCheckController.setEnabled(enabled);
             mSyncRequired = true;
@@ -841,7 +845,10 @@
 
         /**
          * Returns {@code true} if this observer wishes to observe the given package, {@code false}
-         * otherwise
+         * otherwise.
+         * Any failing package can be passed on to the observer. Currently the packages that have
+         * ANRs and perform {@link android.service.watchdog.ExplicitHealthCheckService} are being
+         * passed to observers in these API.
          *
          * <p> A persistent observer may choose to start observing certain failing packages, even if
          * it has not explicitly asked to watch the package with {@link #startObservingHealth}.
@@ -853,14 +860,14 @@
 
     @VisibleForTesting
     long getTriggerFailureCount() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             return mTriggerFailureCount;
         }
     }
 
     @VisibleForTesting
     long getTriggerFailureDurationMs() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             return mTriggerFailureDurationMs;
         }
     }
@@ -881,7 +888,7 @@
      */
     private void syncRequests() {
         boolean syncRequired = false;
-        synchronized (mLock) {
+        synchronized (sLock) {
             if (mIsPackagesReady) {
                 Set<String> packages = getPackagesPendingHealthChecksLocked();
                 if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages)
@@ -918,7 +925,7 @@
         Slog.i(TAG, "Health check passed for package: " + packageName);
         boolean isStateChanged = false;
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) {
                 ObserverInternal observer = mAllObservers.valueAt(observerIdx);
                 MonitoredPackage monitoredPackage = observer.getMonitoredPackage(packageName);
@@ -946,7 +953,7 @@
             supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis());
         }
 
-        synchronized (mLock) {
+        synchronized (sLock) {
             Slog.d(TAG, "Received supported packages " + supportedPackages);
             Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
             while (oit.hasNext()) {
@@ -977,13 +984,13 @@
     }
 
     private void onSyncRequestNotified() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             mSyncRequired = true;
             syncRequestsAsync();
         }
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private Set<String> getPackagesPendingHealthChecksLocked() {
         Set<String> packages = new ArraySet<>();
         Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
@@ -1009,7 +1016,7 @@
      * health check service and schedules the next state sync.
      */
     private void syncState(String reason) {
-        synchronized (mLock) {
+        synchronized (sLock) {
             Slog.i(TAG, "Syncing state, reason: " + reason);
             pruneObserversLocked();
 
@@ -1025,7 +1032,7 @@
         syncState("scheduled");
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private void scheduleNextSyncStateLocked() {
         long durationMs = getNextStateSyncMillisLocked();
         mShortTaskHandler.removeCallbacks(mSyncStateWithScheduledReason);
@@ -1043,7 +1050,7 @@
      *
      * @returns Long#MAX_VALUE if there are no observed packages.
      */
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private long getNextStateSyncMillisLocked() {
         long shortestDurationMs = Long.MAX_VALUE;
         for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
@@ -1064,7 +1071,7 @@
      * Removes {@code elapsedMs} milliseconds from all durations on monitored packages
      * and updates other internal state.
      */
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     private void pruneObserversLocked() {
         long elapsedMs = mUptimeAtLastStateSync == 0
                 ? 0 : mSystemClock.uptimeMillis() - mUptimeAtLastStateSync;
@@ -1092,7 +1099,7 @@
     private void onHealthCheckFailed(ObserverInternal observer,
             Set<MonitoredPackage> failedPackages) {
         mLongTaskHandler.post(() -> {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 PackageHealthObserver registeredObserver = observer.registeredObserver;
                 if (registeredObserver != null) {
                     Iterator<MonitoredPackage> it = failedPackages.iterator();
@@ -1201,7 +1208,7 @@
      */
     @VisibleForTesting
     void updateConfigs() {
-        synchronized (mLock) {
+        synchronized (sLock) {
             mTriggerFailureCount = DeviceConfig.getInt(
                     DeviceConfig.NAMESPACE_ROLLBACK,
                     PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
@@ -1230,7 +1237,7 @@
      */
     private boolean saveToFile() {
         Slog.i(TAG, "Saving observer state to file");
-        synchronized (mLock) {
+        synchronized (sLock) {
             FileOutputStream stream;
             try {
                 stream = mPolicyFile.startWrite();
@@ -1297,20 +1304,38 @@
 
     /** Dump status of every observer in mAllObservers. */
     public void dump(@NonNull PrintWriter pw) {
-        if (Flags.synchronousRebootInRescueParty() && RescueParty.isRecoveryTriggeredReboot()) {
+        if (Flags.synchronousRebootInRescueParty() && isRecoveryTriggeredReboot()) {
             dumpInternal(pw);
         } else {
-            synchronized (mLock) {
+            synchronized (sLock) {
                 dumpInternal(pw);
             }
         }
     }
 
+    /**
+     * Check if we're currently attempting to reboot during mitigation. This method must return
+     * true if triggered reboot early during a boot loop, since the device will not be fully booted
+     * at this time.
+     * @hide
+     */
+    public static boolean isRecoveryTriggeredReboot() {
+        return isFactoryResetPropertySet() || isRebootPropertySet();
+    }
+
+    private static boolean isFactoryResetPropertySet() {
+        return CrashRecoveryProperties.attemptingFactoryReset().orElse(false);
+    }
+
+    private static boolean isRebootPropertySet() {
+        return CrashRecoveryProperties.attemptingReboot().orElse(false);
+    }
+
     private void dumpInternal(@NonNull PrintWriter pw) {
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         ipw.println("Package Watchdog status");
         ipw.increaseIndent();
-        synchronized (mLock) {
+        synchronized (sLock) {
             for (String observerName : mAllObservers.keySet()) {
                 ipw.println("Observer name: " + observerName);
                 ipw.increaseIndent();
@@ -1324,7 +1349,7 @@
     }
 
     @VisibleForTesting
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     void registerObserverInternal(ObserverInternal observerInternal) {
         mAllObservers.put(observerInternal.name, observerInternal);
     }
@@ -1333,15 +1358,15 @@
      * Represents an observer monitoring a set of packages along with the failure thresholds for
      * each package.
      *
-     * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+     * <p> Note, the PackageWatchdog#sLock must always be held when reading or writing
      * instances of this class.
      */
     static class ObserverInternal {
         public final String name;
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
         @Nullable
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public PackageHealthObserver registeredObserver;
         private int mMitigationCount;
 
@@ -1359,7 +1384,7 @@
          * Writes important {@link MonitoredPackage} details for this observer to file.
          * Does not persist any package failure thresholds.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean writeLocked(XmlSerializer out) {
             try {
                 out.startTag(null, TAG_OBSERVER);
@@ -1387,7 +1412,7 @@
             mMitigationCount = mitigationCount;
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public void updatePackagesLocked(List<MonitoredPackage> packages) {
             for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                 MonitoredPackage p = packages.get(pIndex);
@@ -1410,7 +1435,7 @@
          * health check passing, or an empty list if no package expired for which an explicit health
          * check was still pending
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) {
             Set<MonitoredPackage> failedPackages = new ArraySet<>();
             Iterator<MonitoredPackage> it = mPackages.values().iterator();
@@ -1435,7 +1460,7 @@
          * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
          * @hide
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean onPackageFailureLocked(String packageName) {
             if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
                     && registeredObserver.mayObservePackage(packageName)) {
@@ -1454,7 +1479,7 @@
          *
          * @return a mapping of package names to {@link MonitoredPackage} objects.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public ArrayMap<String, MonitoredPackage> getMonitoredPackages() {
             return mPackages;
         }
@@ -1467,7 +1492,7 @@
          * @return the {@link MonitoredPackage} object associated with the package name if one
          *         exists, {@code null} otherwise.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         @Nullable
         public MonitoredPackage getMonitoredPackage(String packageName) {
             return mPackages.get(packageName);
@@ -1478,7 +1503,7 @@
          *
          * @param p: the {@link MonitoredPackage} to store.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public void putMonitoredPackage(MonitoredPackage p) {
             mPackages.put(p.getName(), p);
         }
@@ -1601,17 +1626,17 @@
      * Represents a package and its health check state along with the time
      * it should be monitored for.
      *
-     * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
+     * <p> Note, the PackageWatchdog#sLock must always be held when reading or writing
      * instances of this class.
      */
     class MonitoredPackage {
         private final String mPackageName;
         // Times when package failures happen sorted in ascending order
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private final LongArrayQueue mFailureHistory = new LongArrayQueue();
         // Times when an observer was called to mitigate this package's failure. Sorted in
         // ascending order.
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private final LongArrayQueue mMitigationCalls;
         // One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
         // methods that could change the health check state: handleElapsedTimeLocked and
@@ -1620,17 +1645,17 @@
         // Whether an explicit health check has passed.
         // This value in addition with mHealthCheckDurationMs determines the health check state
         // of the package, see #getHealthCheckStateLocked
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private boolean mHasPassedHealthCheck;
         // System uptime duration to monitor package.
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private long mDurationMs;
         // System uptime duration to check the result of an explicit health check
         // Initially, MAX_VALUE until we get a value from the health check service
         // and request health checks.
         // This value in addition with mHasPassedHealthCheck determines the health check state
         // of the package, see #getHealthCheckStateLocked
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private long mHealthCheckDurationMs = Long.MAX_VALUE;
 
         MonitoredPackage(String packageName, long durationMs,
@@ -1647,7 +1672,7 @@
         /** Writes the salient fields to disk using {@code out}.
          * @hide
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public void writeLocked(XmlSerializer out) throws IOException {
             out.startTag(null, TAG_PACKAGE);
             out.attribute(null, ATTR_NAME, getName());
@@ -1665,7 +1690,7 @@
          *
          * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean onFailureLocked() {
             // Sliding window algorithm: find out if there exists a window containing failures >=
             // mTriggerFailureCount.
@@ -1685,7 +1710,7 @@
         /**
          * Notes the timestamp of a mitigation call into the observer.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public void noteMitigationCallLocked() {
             mMitigationCalls.addLast(mSystemClock.uptimeMillis());
         }
@@ -1696,7 +1721,7 @@
          *
          * @return the number of mitigation calls made in the de-escalation window.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public int getMitigationCountLocked() {
             try {
                 final long now = mSystemClock.uptimeMillis();
@@ -1716,7 +1741,7 @@
          *
          * @return a LongArrayQueue of the mitigation calls relative to the current system uptime.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public LongArrayQueue normalizeMitigationCalls() {
             LongArrayQueue normalized = new LongArrayQueue();
             final long now = mSystemClock.uptimeMillis();
@@ -1731,7 +1756,7 @@
          *
          * @return the new health check state
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
             if (initialHealthCheckDurationMs <= 0) {
                 Slog.wtf(TAG, "Cannot set non-positive health check duration "
@@ -1751,7 +1776,7 @@
          *
          * @return the new health check state
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public int handleElapsedTimeLocked(long elapsedMs) {
             if (elapsedMs <= 0) {
                 Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName());
@@ -1769,7 +1794,7 @@
         }
 
         /** Explicitly update the monitoring duration of the package. */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public void updateHealthCheckDuration(long newDurationMs) {
             mDurationMs = newDurationMs;
         }
@@ -1780,7 +1805,7 @@
          *
          * @return the new {@link HealthCheckState health check state}
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         @HealthCheckState
         public int tryPassHealthCheckLocked() {
             if (mHealthCheckState != HealthCheckState.FAILED) {
@@ -1799,7 +1824,7 @@
         /**
          * Returns the current {@link HealthCheckState health check state}.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         @HealthCheckState
         public int getHealthCheckStateLocked() {
             return mHealthCheckState;
@@ -1810,7 +1835,7 @@
          *
          * @return the duration or {@link Long#MAX_VALUE} if the package should not be scheduled
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public long getShortestScheduleDurationMsLocked() {
             // Consider health check duration only if #isPendingHealthChecksLocked is true
             return Math.min(toPositive(mDurationMs),
@@ -1822,7 +1847,7 @@
          * Returns {@code true} if the total duration left to monitor the package is less than or
          * equal to 0 {@code false} otherwise.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean isExpiredLocked() {
             return mDurationMs <= 0;
         }
@@ -1831,7 +1856,7 @@
          * Returns {@code true} if the package, {@link #getName} is expecting health check results
          * {@code false} otherwise.
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean isPendingHealthChecksLocked() {
             return mHealthCheckState == HealthCheckState.ACTIVE
                     || mHealthCheckState == HealthCheckState.INACTIVE;
@@ -1843,7 +1868,7 @@
          *
          * @return the new {@link HealthCheckState health check state}
          */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         @HealthCheckState
         private int updateHealthCheckStateLocked() {
             int oldState = mHealthCheckState;
@@ -1898,7 +1923,7 @@
         }
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("sLock")
     @SuppressWarnings("GuardedBy")
     void saveAllObserversBootMitigationCountToMetadata(String filePath) {
         HashMap<String, Integer> bootMitigationCounts = new HashMap<>();
@@ -2001,7 +2026,7 @@
 
 
         /** Increments the boot counter, and returns whether the device is bootlooping. */
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         public boolean incrementAndTest() {
             if (Flags.recoverabilityDetection()) {
                 readAllObserversBootMitigationCountIfNecessary(METADATA_FILE);
@@ -2042,7 +2067,7 @@
             }
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private boolean performedMitigationsDuringWindow() {
             for (ObserverInternal observerInternal: mAllObservers.values()) {
                 if (observerInternal.getBootMitigationCount() > 0) {
@@ -2052,7 +2077,7 @@
             return false;
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         private void resetAllObserversBootMitigationCount() {
             for (int i = 0; i < mAllObservers.size(); i++) {
                 final ObserverInternal observer = mAllObservers.valueAt(i);
@@ -2061,7 +2086,7 @@
             saveAllObserversBootMitigationCountToMetadata(METADATA_FILE);
         }
 
-        @GuardedBy("mLock")
+        @GuardedBy("sLock")
         @SuppressWarnings("GuardedBy")
         void readAllObserversBootMitigationCountIfNecessary(String filePath) {
             File metadataFile = new File(filePath);
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/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt
deleted file mode 100644
index e70ec5b..0000000
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesObservable.kt
+++ /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 com.android.settingslib.datastore
-
-import android.content.SharedPreferences
-
-/** [SharedPreferences] based [KeyedDataObservable]. */
-class SharedPreferencesObservable(private val sharedPreferences: SharedPreferences) :
-    KeyedDataObservable<String>(), AutoCloseable {
-
-    private val listener = createSharedPreferenceListener()
-
-    init {
-        sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
-    }
-
-    override fun close() {
-        sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener)
-    }
-}
-
-/** Creates [SharedPreferences.OnSharedPreferenceChangeListener] for [KeyedObservable]. */
-internal fun KeyedObservable<String>.createSharedPreferenceListener() =
-    SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
-        if (key != null) {
-            notifyChange(key, DataChangeReason.UPDATE)
-        } else {
-            // On Android >= R, SharedPreferences.Editor.clear() will trigger this case
-            notifyChange(DataChangeReason.DELETE)
-        }
-    }
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..7aece51 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, myUid, callingUid, 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()
     }
 }
 
@@ -64,16 +68,18 @@
     val screenKeys: Set<String> = setOf(),
     val visitedScreens: Set<String> = setOf(),
     val locale: Locale? = null,
-    val includeValue: Boolean = true,
+    val flags: Int = PreferenceGetterFlags.ALL,
+    val includeValue: Boolean = true, // TODO: clean up
     val includeValueDescriptor: Boolean = true,
 )
 
 object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
     override fun encode(data: GetPreferenceGraphRequest): Bundle =
-        Bundle(3).apply {
+        Bundle(4).apply {
             putStringArray(KEY_SCREEN_KEYS, data.screenKeys.toTypedArray())
             putStringArray(KEY_VISITED_KEYS, data.visitedScreens.toTypedArray())
             putString(KEY_LOCALE, data.locale?.toLanguageTag())
+            putInt(KEY_FLAGS, data.flags)
         }
 
     override fun decode(data: Bundle): GetPreferenceGraphRequest {
@@ -84,12 +90,14 @@
             screenKeys.toSet(),
             visitedScreens.toSet(),
             data.getString(KEY_LOCALE).toLocale(),
+            data.getInt(KEY_FLAGS),
         )
     }
 
     private const val KEY_SCREEN_KEYS = "k"
     private const val KEY_VISITED_KEYS = "v"
     private const val KEY_LOCALE = "l"
+    private const val KEY_FLAGS = "f"
 }
 
 object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt
new file mode 100644
index 0000000..68aa2d2
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceCoordinate.kt
@@ -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.
+ */
+
+package com.android.settingslib.graph
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Coordinate to locate a preference.
+ *
+ * Within an app, the preference screen key (unique among screens) plus preference key (unique on
+ * the screen) is used to locate a preference.
+ */
+data class PreferenceCoordinate(val screenKey: String, val key: String) : Parcelable {
+
+    constructor(parcel: Parcel) : this(parcel.readString()!!, parcel.readString()!!)
+
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeString(screenKey)
+        parcel.writeString(key)
+    }
+
+    override fun describeContents() = 0
+
+    companion object CREATOR : Parcelable.Creator<PreferenceCoordinate> {
+
+        override fun createFromParcel(parcel: Parcel) = PreferenceCoordinate(parcel)
+
+        override fun newArray(size: Int) = arrayOfNulls<PreferenceCoordinate>(size)
+    }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt
new file mode 100644
index 0000000..c8453ef
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterApi.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.graph
+
+import android.app.Application
+import androidx.annotation.IntDef
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.ipc.ApiDescriptor
+import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.ApiPermissionChecker
+import com.android.settingslib.metadata.PreferenceHierarchyNode
+import com.android.settingslib.metadata.PreferenceScreenRegistry
+
+/**
+ * Request to get preference information.
+ *
+ * @param preferences coordinate of preferences
+ * @param flags a combination of constants in [PreferenceGetterFlags]
+ */
+class PreferenceGetterRequest(val preferences: Array<PreferenceCoordinate>, val flags: Int)
+
+/** Error code of preference getter request. */
+@Target(AnnotationTarget.TYPE)
+@IntDef(
+    PreferenceGetterErrorCode.NOT_FOUND,
+    PreferenceGetterErrorCode.DISALLOW,
+    PreferenceGetterErrorCode.INTERNAL_ERROR,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class PreferenceGetterErrorCode {
+    companion object {
+        /** Preference is not found. */
+        const val NOT_FOUND = 1
+        /** Disallow to get preference value (e.g. uid not allowed). */
+        const val DISALLOW = 2
+        /** Internal error happened when get preference information. */
+        const val INTERNAL_ERROR = 3
+
+        fun getMessage(code: Int) =
+            when (code) {
+                NOT_FOUND -> "Preference not found"
+                DISALLOW -> "Disallow to get preference value"
+                INTERNAL_ERROR -> "Internal error"
+                else -> "Unknown error"
+            }
+    }
+}
+
+/** Response of the getter API. */
+class PreferenceGetterResponse(
+    val errors: Map<PreferenceCoordinate, @PreferenceGetterErrorCode Int>,
+    val preferences: Map<PreferenceCoordinate, PreferenceProto>,
+)
+
+/** Preference getter API descriptor. */
+class PreferenceGetterApiDescriptor(override val id: Int) :
+    ApiDescriptor<PreferenceGetterRequest, PreferenceGetterResponse> {
+
+    override val requestCodec = PreferenceGetterRequestCodec()
+
+    override val responseCodec = PreferenceGetterResponseCodec()
+}
+
+/** Preference getter API implementation. */
+class PreferenceGetterApiHandler(
+    override val id: Int,
+    private val permissionChecker: ApiPermissionChecker<PreferenceGetterRequest>,
+) : ApiHandler<PreferenceGetterRequest, PreferenceGetterResponse> {
+
+    override fun hasPermission(
+        application: Application,
+        myUid: Int,
+        callingUid: Int,
+        request: PreferenceGetterRequest,
+    ) = permissionChecker.hasPermission(application, myUid, callingUid, request)
+
+    override suspend fun invoke(
+        application: Application,
+        myUid: Int,
+        callingUid: Int,
+        request: PreferenceGetterRequest,
+    ): PreferenceGetterResponse {
+        val errors = mutableMapOf<PreferenceCoordinate, Int>()
+        val preferences = mutableMapOf<PreferenceCoordinate, PreferenceProto>()
+        val flags = request.flags
+        for ((screenKey, coordinates) in request.preferences.groupBy { it.screenKey }) {
+            val screenMetadata = PreferenceScreenRegistry[screenKey]
+            if (screenMetadata == null) {
+                for (coordinate in coordinates) {
+                    errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND
+                }
+                continue
+            }
+            val nodes = mutableMapOf<String, PreferenceHierarchyNode?>()
+            for (coordinate in coordinates) nodes[coordinate.key] = null
+            screenMetadata.getPreferenceHierarchy(application).forEachRecursively {
+                val metadata = it.metadata
+                val key = metadata.key
+                if (nodes.containsKey(key)) nodes[key] = it
+            }
+            for (coordinate in coordinates) {
+                val node = nodes[coordinate.key]
+                if (node == null) {
+                    errors[coordinate] = PreferenceGetterErrorCode.NOT_FOUND
+                    continue
+                }
+                val metadata = node.metadata
+                try {
+                    val preferenceProto =
+                        metadata.toProto(
+                            application,
+                            myUid,
+                            callingUid,
+                            screenMetadata,
+                            metadata.key == screenMetadata.key,
+                            flags,
+                        )
+                    if (flags == PreferenceGetterFlags.VALUE && !preferenceProto.hasValue()) {
+                        errors[coordinate] = PreferenceGetterErrorCode.DISALLOW
+                    } else {
+                        preferences[coordinate] = preferenceProto
+                    }
+                } catch (e: Exception) {
+                    errors[coordinate] = PreferenceGetterErrorCode.INTERNAL_ERROR
+                }
+            }
+        }
+        return PreferenceGetterResponse(errors, preferences)
+    }
+
+    override val requestCodec = PreferenceGetterRequestCodec()
+
+    override val responseCodec = PreferenceGetterResponseCodec()
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt
new file mode 100644
index 0000000..ff14eb5
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterCodecs.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.graph
+
+import android.os.Bundle
+import android.os.Parcel
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.ipc.MessageCodec
+import java.util.Arrays
+
+/** Message codec for [PreferenceGetterRequest]. */
+class PreferenceGetterRequestCodec : MessageCodec<PreferenceGetterRequest> {
+    override fun encode(data: PreferenceGetterRequest) =
+        Bundle(2).apply {
+            putParcelableArray(null, data.preferences)
+            putInt(FLAGS, data.flags)
+        }
+
+    @Suppress("DEPRECATION")
+    override fun decode(data: Bundle): PreferenceGetterRequest {
+        data.classLoader = PreferenceCoordinate::class.java.classLoader
+        val array = data.getParcelableArray(null)!!
+
+        return PreferenceGetterRequest(
+            Arrays.copyOf(array, array.size, Array<PreferenceCoordinate>::class.java),
+            data.getInt(FLAGS),
+        )
+    }
+
+    companion object {
+        private const val FLAGS = "f"
+    }
+}
+
+/** Message codec for [PreferenceGetterResponse]. */
+class PreferenceGetterResponseCodec : MessageCodec<PreferenceGetterResponse> {
+    override fun encode(data: PreferenceGetterResponse) =
+        Bundle(2).apply {
+            data.errors.toErrorsByteArray()?.let { putByteArray(ERRORS, it) }
+            data.preferences.toPreferencesByteArray()?.let { putByteArray(null, it) }
+        }
+
+    private fun Map<PreferenceCoordinate, Int>.toErrorsByteArray(): ByteArray? {
+        if (isEmpty()) return null
+        val parcel = Parcel.obtain()
+        parcel.writeInt(size)
+        for ((coordinate, code) in this) {
+            coordinate.writeToParcel(parcel, 0)
+            parcel.writeInt(code)
+        }
+        val bytes = parcel.marshall()
+        parcel.recycle()
+        return bytes
+    }
+
+    private fun Map<PreferenceCoordinate, PreferenceProto>.toPreferencesByteArray(): ByteArray? {
+        if (isEmpty()) return null
+        val parcel = Parcel.obtain()
+        parcel.writeInt(size)
+        for ((coordinate, preferenceProto) in this) {
+            coordinate.writeToParcel(parcel, 0)
+            val data = preferenceProto.toByteArray()
+            parcel.writeInt(data.size)
+            parcel.writeByteArray(data)
+        }
+        val bytes = parcel.marshall()
+        parcel.recycle()
+        return bytes
+    }
+
+    override fun decode(data: Bundle) =
+        PreferenceGetterResponse(
+            data.getByteArray(ERRORS).toErrors(),
+            data.getByteArray(null).toPreferences(),
+        )
+
+    private fun ByteArray?.toErrors(): Map<PreferenceCoordinate, Int> {
+        if (this == null) return emptyMap()
+        val parcel = Parcel.obtain()
+        parcel.unmarshall(this, 0, size)
+        parcel.setDataPosition(0)
+        val count = parcel.readInt()
+        val errors = mutableMapOf<PreferenceCoordinate, Int>()
+        repeat(count) {
+            val coordinate = PreferenceCoordinate(parcel)
+            errors[coordinate] = parcel.readInt()
+        }
+        parcel.recycle()
+        return errors
+    }
+
+    private fun ByteArray?.toPreferences(): Map<PreferenceCoordinate, PreferenceProto> {
+        if (this == null) return emptyMap()
+        val parcel = Parcel.obtain()
+        parcel.unmarshall(this, 0, size)
+        parcel.setDataPosition(0)
+        val count = parcel.readInt()
+        val preferences = mutableMapOf<PreferenceCoordinate, PreferenceProto>()
+        repeat(count) {
+            val coordinate = PreferenceCoordinate(parcel)
+            val bytes = parcel.readInt()
+            val array = ByteArray(bytes).also { parcel.readByteArray(it) }
+            preferences[coordinate] = PreferenceProto.parseFrom(array)
+        }
+        parcel.recycle()
+        return preferences
+    }
+
+    companion object {
+        private const val ERRORS = "e"
+    }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt
new file mode 100644
index 0000000..632f154
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGetterFlags.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.graph
+
+/** Flags for preference getter operation. */
+object PreferenceGetterFlags {
+    const val VALUE = 1 shl 0
+    const val VALUE_DESCRIPTOR = 1 shl 1
+    const val METADATA = 1 shl 2
+    const val ALL = (1 shl 3) - 1
+
+    fun Int.includeValue() = (this and VALUE) != 0
+
+    fun Int.includeValueDescriptor() = (this and VALUE_DESCRIPTOR) != 0
+
+    fun Int.includeMetadata() = (this and METADATA) != 0
+}
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..a65d24c 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -31,6 +31,9 @@
 import androidx.preference.PreferenceGroup
 import androidx.preference.PreferenceScreen
 import androidx.preference.TwoStatePreference
+import com.android.settingslib.graph.PreferenceGetterFlags.includeMetadata
+import com.android.settingslib.graph.PreferenceGetterFlags.includeValue
+import com.android.settingslib.graph.PreferenceGetterFlags.includeValueDescriptor
 import com.android.settingslib.graph.proto.PreferenceGraphProto
 import com.android.settingslib.graph.proto.PreferenceGroupProto
 import com.android.settingslib.graph.proto.PreferenceProto
@@ -41,7 +44,6 @@
 import com.android.settingslib.metadata.PersistentPreference
 import com.android.settingslib.metadata.PreferenceAvailabilityProvider
 import com.android.settingslib.metadata.PreferenceHierarchy
-import com.android.settingslib.metadata.PreferenceHierarchyNode
 import com.android.settingslib.metadata.PreferenceMetadata
 import com.android.settingslib.metadata.PreferenceRestrictionProvider
 import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider
@@ -50,6 +52,7 @@
 import com.android.settingslib.metadata.PreferenceSummaryProvider
 import com.android.settingslib.metadata.PreferenceTitleProvider
 import com.android.settingslib.metadata.RangeValue
+import com.android.settingslib.metadata.ReadWritePermit
 import com.android.settingslib.preference.PreferenceScreenFactory
 import com.android.settingslib.preference.PreferenceScreenProvider
 import java.util.Locale
@@ -60,14 +63,17 @@
 
 /** Builder of preference graph. */
 class PreferenceGraphBuilder
-private constructor(private val context: Context, private val request: GetPreferenceGraphRequest) {
+private constructor(
+    private val context: Context,
+    private val myUid: Int,
+    private val callingUid: Int,
+    private val request: GetPreferenceGraphRequest,
+) {
     private val preferenceScreenFactory by lazy {
         PreferenceScreenFactory(context.ofLocale(request.locale))
     }
     private val builder by lazy { PreferenceGraphProto.newBuilder() }
     private val visitedScreens = mutableSetOf<String>().apply { addAll(request.visitedScreens) }
-    private val includeValue = request.includeValue
-    private val includeValueDescriptor = request.includeValueDescriptor
 
     private suspend fun init() {
         for (key in request.screenKeys) {
@@ -133,7 +139,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 +152,7 @@
             }
         }
 
-    private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
+    suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
         Log.d(TAG, "add $activityClass")
         createPreferenceScreen { activityClass.newInstance() }
             ?.let {
@@ -229,7 +235,7 @@
         enabled = isEnabled
         available = isVisible
         persistent = isPersistent
-        if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
+        if (request.flags.includeValue() && isPersistent && this@toProto is TwoStatePreference) {
             value = preferenceValueProto { booleanValue = this@toProto.isChecked }
         }
         this@toProto.fragment.toActionTarget(preferenceExtras)?.let {
@@ -243,14 +249,14 @@
         screenMetadata: PreferenceScreenMetadata,
         isRoot: Boolean,
     ): PreferenceGroupProto = preferenceGroupProto {
-        preference = toProto(screenMetadata, this@toProto, isRoot)
+        preference = toProto(screenMetadata, this@toProto.metadata, isRoot)
         forEachAsync {
             addPreferences(
                 preferenceOrGroupProto {
                     if (it is PreferenceHierarchy) {
                         group = it.toProto(screenMetadata, false)
                     } else {
-                        preference = toProto(screenMetadata, it, false)
+                        preference = toProto(screenMetadata, it.metadata, false)
                     }
                 }
             )
@@ -259,93 +265,19 @@
 
     private suspend fun toProto(
         screenMetadata: PreferenceScreenMetadata,
-        node: PreferenceHierarchyNode,
+        metadata: PreferenceMetadata,
         isRoot: Boolean,
-    ) = preferenceProto {
-        val metadata = node.metadata
-        key = metadata.key
-        metadata.getTitleTextProto(isRoot)?.let { title = it }
-        if (metadata.summary != 0) {
-            summary = textProto { resourceId = metadata.summary }
-        } else {
-            (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
-                summary = textProto { string = it.toString() }
+    ) =
+        metadata.toProto(context, myUid, callingUid, screenMetadata, isRoot, request.flags).also {
+            if (metadata is PreferenceScreenMetadata) {
+                @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata)
             }
-        }
-        val metadataIcon = metadata.getPreferenceIcon(context)
-        if (metadataIcon != 0) icon = metadataIcon
-        if (metadata.keywords != 0) keywords = metadata.keywords
-        val preferenceExtras = metadata.extras(context)
-        preferenceExtras?.let { extras = it.toProto() }
-        indexable = metadata.isIndexable(context)
-        enabled = metadata.isEnabled(context)
-        if (metadata is PreferenceAvailabilityProvider) {
-            available = metadata.isAvailable(context)
-        }
-        if (metadata is PreferenceRestrictionProvider) {
-            restricted = metadata.isRestricted(context)
-        }
-        persistent = metadata.isPersistent(context)
-        if (persistent) {
-            if (includeValue && metadata is PersistentPreference<*>) {
-                value = preferenceValueProto {
-                    when (metadata) {
-                        is BooleanValue ->
-                            metadata
-                                .storage(context)
-                                .getValue(metadata.key, Boolean::class.javaObjectType)
-                                ?.let { booleanValue = it }
-                        is RangeValue -> {
-                            metadata
-                                .storage(context)
-                                .getValue(metadata.key, Int::class.javaObjectType)
-                                ?.let { intValue = it }
-                        }
-                        else -> {}
-                    }
-                }
-            }
-            if (includeValueDescriptor) {
-                valueDescriptor = preferenceValueDescriptorProto {
-                    when (metadata) {
-                        is BooleanValue -> booleanType = true
-                        is RangeValue -> rangeValue = rangeValueProto {
-                                min = metadata.getMinValue(context)
-                                max = metadata.getMaxValue(context)
-                                step = metadata.getIncrementStep(context)
-                            }
-                        else -> {}
-                    }
+            metadata.intent(context)?.resolveActivity(context.packageManager)?.let {
+                if (it.packageName == context.packageName) {
+                    add(it.className)
                 }
             }
         }
-        if (metadata is PreferenceScreenMetadata) {
-            @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata)
-        }
-        metadata.intent(context)?.let { actionTarget = it.toActionTarget() }
-        screenMetadata.getLaunchIntent(context, metadata)?.let { launchIntent = it.toProto() }
-    }
-
-    private fun PreferenceMetadata.getTitleTextProto(isRoot: Boolean): TextProto? {
-        if (isRoot && this is PreferenceScreenMetadata) {
-            val titleRes = screenTitle
-            if (titleRes != 0) {
-                return textProto { resourceId = titleRes }
-            } else {
-                getScreenTitle(context)?.let {
-                    return textProto { string = it.toString() }
-                }
-            }
-        } else {
-            val titleRes = title
-            if (titleRes != 0) {
-                return textProto { resourceId = titleRes }
-            }
-        }
-        return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
-            textProto { string = it.toString() }
-        }
-    }
 
     private suspend fun String?.toActionTarget(extras: Bundle?): ActionTarget? {
         if (this.isNullOrEmpty()) return null
@@ -399,24 +331,131 @@
         return null
     }
 
-    private suspend fun Intent.toActionTarget(): ActionTarget {
-        if (component?.packageName == "") {
-            setClassName(context, component!!.className)
-        }
-        resolveActivity(context.packageManager)?.let {
-            if (it.packageName == context.packageName) {
-                add(it.className)
+    private suspend fun Intent.toActionTarget() =
+        toActionTarget(context).also {
+            resolveActivity(context.packageManager)?.let {
+                if (it.packageName == context.packageName) {
+                    add(it.className)
+                }
             }
         }
-        return actionTargetProto { intent = toProto() }
-    }
 
     companion object {
-        suspend fun of(context: Context, request: GetPreferenceGraphRequest) =
-            PreferenceGraphBuilder(context, request).also { it.init() }
+        suspend fun of(
+            context: Context,
+            myUid: Int,
+            callingUid: Int,
+            request: GetPreferenceGraphRequest,
+        ) = PreferenceGraphBuilder(context, myUid, callingUid, request).also { it.init() }
     }
 }
 
+fun PreferenceMetadata.toProto(
+    context: Context,
+    myUid: Int,
+    callingUid: Int,
+    screenMetadata: PreferenceScreenMetadata,
+    isRoot: Boolean,
+    flags: Int,
+) = preferenceProto {
+    val metadata = this@toProto
+    key = metadata.key
+    if (flags.includeMetadata()) {
+        metadata.getTitleTextProto(context, isRoot)?.let { title = it }
+        if (metadata.summary != 0) {
+            summary = textProto { resourceId = metadata.summary }
+        } else {
+            (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
+                summary = textProto { string = it.toString() }
+            }
+        }
+        val metadataIcon = metadata.getPreferenceIcon(context)
+        if (metadataIcon != 0) icon = metadataIcon
+        if (metadata.keywords != 0) keywords = metadata.keywords
+        val preferenceExtras = metadata.extras(context)
+        preferenceExtras?.let { extras = it.toProto() }
+        indexable = metadata.isIndexable(context)
+        enabled = metadata.isEnabled(context)
+        if (metadata is PreferenceAvailabilityProvider) {
+            available = metadata.isAvailable(context)
+        }
+        if (metadata is PreferenceRestrictionProvider) {
+            restricted = metadata.isRestricted(context)
+        }
+        metadata.intent(context)?.let { actionTarget = it.toActionTarget(context) }
+        screenMetadata.getLaunchIntent(context, metadata)?.let { launchIntent = it.toProto() }
+    }
+    persistent = metadata.isPersistent(context)
+    if (persistent) {
+        if (
+            flags.includeValue() &&
+                enabled &&
+                (!hasAvailable() || available) &&
+                (!hasRestricted() || !restricted) &&
+                metadata is PersistentPreference<*> &&
+                metadata.getReadPermit(context, myUid, callingUid) == ReadWritePermit.ALLOW
+        ) {
+            value = preferenceValueProto {
+                when (metadata) {
+                    is BooleanValue ->
+                        metadata
+                            .storage(context)
+                            .getValue(metadata.key, Boolean::class.javaObjectType)
+                            ?.let { booleanValue = it }
+                    is RangeValue -> {
+                        metadata
+                            .storage(context)
+                            .getValue(metadata.key, Int::class.javaObjectType)
+                            ?.let { intValue = it }
+                    }
+                    else -> {}
+                }
+            }
+        }
+        if (flags.includeValueDescriptor()) {
+            valueDescriptor = preferenceValueDescriptorProto {
+                when (metadata) {
+                    is BooleanValue -> booleanType = true
+                    is RangeValue -> rangeValue = rangeValueProto {
+                            min = metadata.getMinValue(context)
+                            max = metadata.getMaxValue(context)
+                            step = metadata.getIncrementStep(context)
+                        }
+                    else -> {}
+                }
+            }
+        }
+    }
+}
+
+private fun PreferenceMetadata.getTitleTextProto(context: Context, isRoot: Boolean): TextProto? {
+    if (isRoot && this is PreferenceScreenMetadata) {
+        val titleRes = screenTitle
+        if (titleRes != 0) {
+            return textProto { resourceId = titleRes }
+        } else {
+            getScreenTitle(context)?.let {
+                return textProto { string = it.toString() }
+            }
+        }
+    } else {
+        val titleRes = title
+        if (titleRes != 0) {
+            return textProto { resourceId = titleRes }
+        }
+    }
+    return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
+        textProto { string = it.toString() }
+    }
+}
+
+private fun Intent.toActionTarget(context: Context): ActionTarget {
+    if (component?.packageName == "") {
+        setClassName(context, component!!.className)
+    }
+    return actionTargetProto { intent = toProto() }
+}
+
 @SuppressLint("AppBundleLocaleChanges")
 internal fun Context.ofLocale(locale: Locale?): Context {
     if (locale == null) return this
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/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
index a2b826a..9179f8f 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceHierarchy.kt
@@ -58,6 +58,9 @@
     /** Specifies preference order in the hierarchy. */
     infix fun PreferenceHierarchyNode.order(order: Int) = apply { this.order = order }
 
+    /** Specifies preference order in the hierarchy for group. */
+    infix fun PreferenceHierarchy.order(order: Int) = apply { this.order = order }
+
     /** Adds a preference to the hierarchy. */
     @JvmOverloads
     fun add(metadata: PreferenceMetadata, order: Int? = null) {
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..7cb36db 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,16 @@
 
 package com.android.settingslib.service
 
+import com.android.settingslib.graph.GetPreferenceGraphRequest
+import com.android.settingslib.graph.PreferenceGetterApiHandler
+import com.android.settingslib.graph.PreferenceGetterRequest
 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 +34,25 @@
  * [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,
+    getterPermissionChecker: ApiPermissionChecker<PreferenceGetterRequest>? = 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))
+            }
+            getterPermissionChecker?.let {
+                add(PreferenceGetterApiHandler(API_PREFERENCE_GETTER, 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..d71405e 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,17 @@
 
 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
+
+/** API id for preference getter. */
+internal const val API_PREFERENCE_GETTER = 3
+
+/**
+ * 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/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
index e883a4a..25bb46c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/ModifierExt.kt
@@ -25,3 +25,36 @@
     if (contentDescription != null) this.semantics {
         this.contentDescription = contentDescription
     } else this
+
+/**
+ * Concatenates this modifier with another if `condition` is true.
+ *
+ * This method allows inline conditional addition of modifiers to a modifier chain. Instead of
+ * writing
+ *
+ * ```
+ * val aModifier = Modifier.a()
+ * val bModifier = if(condition) aModifier.b() else aModifier
+ * Composable(modifier = bModifier)
+ * ```
+ *
+ * You can instead write
+ *
+ * ```
+ * Composable(modifier = Modifier.a().thenIf(condition){
+ *   Modifier.b()
+ * }
+ * ```
+ *
+ * This makes the modifier chain easier to read.
+ *
+ * Note that unlike the non-factory version, the conditional modifier is recreated each time, and
+ * may never be created at all.
+ *
+ * @param condition Whether or not to apply the modifiers.
+ * @param factory Creates the modifier to concatenate with the current one.
+ * @return a Modifier representing this modifier followed by other in sequence.
+ * @see Modifier.then
+ */
+inline fun Modifier.thenIf(condition: Boolean, crossinline factory: () -> Modifier): Modifier =
+    if (condition) this.then(factory()) else this
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
index acb96be..b1bb79d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt
@@ -36,12 +36,13 @@
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.min
+import com.android.settingslib.spa.framework.compose.thenIf
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsOpacity.alphaForEnabled
 import com.android.settingslib.spa.framework.theme.SettingsShape
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
+import com.android.settingslib.spa.widget.ui.LocalIsInCategory
 import com.android.settingslib.spa.widget.ui.SettingsTitle
 
 @Composable
@@ -57,18 +58,18 @@
     paddingVertical: Dp = SettingsDimension.itemPaddingVertical,
     widget: @Composable () -> Unit = {},
 ) {
+    val surfaceBright = MaterialTheme.colorScheme.surfaceBright
     Row(
         modifier =
             modifier
                 .fillMaxWidth()
                 .semantics(mergeDescendants = true) {}
-                .then(
-                    if (isSpaExpressiveEnabled)
-                        Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
-                            .clip(SettingsShape.CornerExtraSmall)
-                            .background(MaterialTheme.colorScheme.surfaceBright)
-                    else Modifier
-                )
+                .thenIf(isSpaExpressiveEnabled) {
+                    Modifier.heightIn(min = SettingsDimension.preferenceMinHeight)
+                }
+                .thenIf(isSpaExpressiveEnabled && LocalIsInCategory.current) {
+                    Modifier.clip(SettingsShape.CornerExtraSmall).background(surfaceBright)
+                }
                 .padding(end = paddingEnd),
         verticalAlignment = Alignment.CenterVertically,
     ) {
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 28b2b4a..96d2abb 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
@@ -31,6 +31,8 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -99,7 +101,7 @@
             verticalArrangement =
                 if (isSpaExpressiveEnabled) Arrangement.spacedBy(SettingsDimension.paddingTiny)
                 else Arrangement.Top,
-            content = content,
+            content = { CompositionLocalProvider(LocalIsInCategory provides true) { content() } },
         )
     }
 }
@@ -109,15 +111,14 @@
  *
  * @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 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>,
@@ -144,17 +145,19 @@
             verticalArrangement = Arrangement.spacedBy(SettingsDimension.paddingTiny),
             state = state,
         ) {
-            item { content() }
+            item { CompositionLocalProvider(LocalIsInCategory provides true) { content() } }
 
             items(count = list.size, key = key) {
                 title?.invoke(it)?.let { title -> CategoryTitle(title) }
-                val entryPreference = entry(it)
-                entryPreference()
+                CompositionLocalProvider(LocalIsInCategory provides true) { entry(it)() }
             }
         }
     }
 }
 
+/** LocalIsInCategory containing the if the current composable is in a category. */
+internal val LocalIsInCategory = compositionLocalOf { false }
+
 @Preview
 @Composable
 private fun CategoryPreview() {
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index bf419cc..076f82a 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -171,3 +171,10 @@
     description: "Enable the user consent prompt before writing sensitive preferences via service"
     bug: "378552675"
 }
+
+flag {
+    name: "hearing_devices_input_routing_control"
+    namespace: "accessibility"
+    description: "Enable the input routing control in device details and hearing devices dialog."
+    bug: "349255906"
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index d0827b3..4eb0567 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -133,8 +133,9 @@
      * If an ACTION_UUID intent comes in within
      * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
      * again with the new UUIDs
+     * The value is reset if a manual disconnection happens.
      */
-    private long mConnectAttempted;
+    private long mConnectAttempted = -1;
 
     // Active device state
     private boolean mIsActiveDeviceA2dp = false;
@@ -369,6 +370,7 @@
     }
 
     public void disconnect() {
+        mConnectAttempted = -1;
         synchronized (mProfileLock) {
             if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
                 for (CachedBluetoothDevice member : getMemberDevice()) {
@@ -983,15 +985,19 @@
         }
 
         if (BluetoothUtils.D) {
-            Log.d(TAG, "onUuidChanged: Time since last connect="
-                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
+            long lastConnectAttempted = mConnectAttempted == -1 ? 0 : mConnectAttempted;
+            Log.d(
+                    TAG,
+                    "onUuidChanged: Time since last connect/manual disconnect="
+                            + (SystemClock.elapsedRealtime() - lastConnectAttempted));
         }
 
         /*
          * If a connect was attempted earlier without any UUID, we will do the connect now.
          * Otherwise, allow the connect on UUID change.
          */
-        if ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
+        if (mConnectAttempted != -1
+                && (mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) {
             Log.d(TAG, "onUuidChanged: triggering connectDevice");
             connectDevice();
         }
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 34d3bd9..d5cfe55 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -208,6 +208,11 @@
     }
 
     @NonNull
+    public Kind getKind() {
+        return mKind;
+    }
+
+    @NonNull
     public Status getStatus() {
         return mStatus;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
index b41e970..4c4ce2a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
@@ -221,6 +221,7 @@
     override suspend fun audioSharingAvailable(): Boolean {
         return withContext(backgroundCoroutineContext) {
             BluetoothUtils.isAudioSharingEnabled()
+                    || BluetoothUtils.isAudioSharingPreviewEnabled(contentResolver)
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
index 18a4c6d..791d866 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
@@ -26,4 +26,6 @@
     fun onVolumeMapChanged(map: Map<Int, Int>)
 
     fun onSetDeviceVolumeRequested(volume: Int)
+
+    fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String)
 }
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
index cc4cc8d..731b3a1 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
@@ -43,4 +43,8 @@
     override fun onSetDeviceVolumeRequested(volume: Int) {
         mutableLogs.add("onSetVolumeRequested volume=$volume")
     }
+
+    override fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String) {
+        mutableLogs.add("onAudioSharingAvailabilityRequestedError, requestFrom=$requestFrom")
+    }
 }
\ No newline at end of file
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/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/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 8f58e8c..c90ba82 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -462,5 +462,7 @@
                 Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE_NONE,
                 Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE_COMPANION
         ));
+        VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_NOTIFICATION, ANY_STRING_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 558ccaf..509b88b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -263,6 +263,5 @@
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_ALL, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_COOLDOWN_VIBRATE_UNLOCKED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(System.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, ANY_STRING_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c2beaa8..9de7faf 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -564,6 +564,8 @@
                     Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
                     Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
                     Settings.Global.ENABLE_BACK_ANIMATION, // Temporary for T, dev option only
+                    Settings.Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, // cache per hearing device
+                    Settings.Global.HEARING_DEVICE_LOCAL_NOTIFICATION, // cache per hearing device
                     Settings.Global.Wearable.COMBINED_LOCATION_ENABLE,
                     Settings.Global.Wearable.HAS_PAY_TOKENS,
                     Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
@@ -944,8 +946,7 @@
                         Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE,
                         Settings.System.WEAR_TTS_PREWARM_ENABLED,
                         Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
-                        Settings.System.MULTI_AUDIO_FOCUS_ENABLED, // form-factor/OEM specific
-                        Settings.System.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME // internal cache
+                        Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific
                 );
         if (!Flags.backUpSmoothDisplayAndForcePeakRefreshRate()) {
             settings.add(Settings.System.MIN_REFRESH_RATE);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7b6321d..1070ebd 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" />
 
@@ -743,6 +746,9 @@
     <!-- Permission required for ATS test - CarDevicePolicyManagerTest -->
     <uses-permission android:name="android.permission.LOCK_DEVICE" />
 
+    <!-- Permission required for AuthenticationPolicyManagerTest -->
+    <uses-permission android:name="android.permission.MANAGE_SECURE_LOCK_DEVICE" />
+
     <!-- Permissions required for CTS test - CtsSafetyCenterTestCases -->
     <uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
     <uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
@@ -953,6 +959,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/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/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index dafe38d..d1a22e8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -208,7 +208,9 @@
         "tests/src/**/systemui/qs/tiles/DreamTileTest.java",
         "tests/src/**/systemui/qs/FgsManagerControllerTest.java",
         "tests/src/**/systemui/qs/QSPanelTest.kt",
+        "tests/src/**/systemui/reardisplay/RearDisplayCoreStartableTest.kt",
         "tests/src/**/systemui/reardisplay/RearDisplayDialogControllerTest.java",
+        "tests/src/**/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt",
         "tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java",
         "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
         "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a4b8821..67666c3d 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -632,9 +632,9 @@
 
 flag {
   name: "status_bar_connected_displays"
-  namespace: "systemui"
+  namespace: "lse_desktop_experience"
   description: "Shows the status bar on connected displays"
-  bug: "362720336"
+  bug: "379264862"
 }
 
 flag {
@@ -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/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 96e99b1..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
@@ -67,6 +67,7 @@
                             dialogFactory = dialogFactory,
                             widgetSection = widgetSection,
                             modifier = Modifier.element(Communal.Elements.Grid),
+                            sceneScope = this@Content,
                         )
                     }
                     with(lockSection) {
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 df1185c..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) }
@@ -871,6 +877,7 @@
                     interactionHandler = interactionHandler,
                     widgetSection = widgetSection,
                     resizeableItemFrameViewModel = resizeableItemFrameViewModel,
+                    sceneScope = sceneScope,
                 )
             }
         }
@@ -1095,6 +1102,7 @@
     interactionHandler: RemoteViews.InteractionHandler?,
     widgetSection: CommunalAppWidgetSection,
     resizeableItemFrameViewModel: ResizeableItemFrameViewModel,
+    sceneScope: SceneScope? = null,
 ) {
     when (model) {
         is CommunalContentModel.WidgetContent.Widget ->
@@ -1118,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)
     }
 }
 
@@ -1529,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/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 1551ca9..ef5e90b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -179,11 +179,18 @@
         val targetItem =
             if (communalWidgetResizing()) {
                 state.layoutInfo.visibleItemsInfo.findLast { item ->
+                    val lastVisibleItemIndex = state.layoutInfo.visibleItemsInfo.last().index
                     val itemBoundingBox = IntRect(item.offset, item.size)
                     draggingItemKey != item.key &&
                         contentListState.isItemEditable(item.index) &&
                         (draggingBoundingBox.contains(itemBoundingBox.center) ||
-                            itemBoundingBox.contains(draggingBoundingBox.center))
+                            itemBoundingBox.contains(draggingBoundingBox.center)) &&
+                        // If we swap with the last visible item, and that item doesn't fit
+                        // in the gap created by moving the current item, then the current item
+                        // will get placed after the last visible item. In this case, it gets
+                        // placed outside of the viewport. We avoid this here, so the user
+                        // has to scroll first before the swap can happen.
+                        (item.index != lastVisibleItemIndex || item.span <= draggingItem.span)
                 }
             } else {
                 state.layoutInfo.visibleItemsInfo
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/shade/ui/composable/SingleShadeMeasurePolicy.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
index 352d29e2..7489648 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
@@ -25,7 +25,6 @@
 import androidx.compose.ui.layout.layoutId
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.offset
-import androidx.compose.ui.util.fastFirst
 import androidx.compose.ui.util.fastFirstOrNull
 import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy.LayoutId
 import kotlin.math.max
@@ -60,18 +59,20 @@
 
         val shadeHeaderPlaceable =
             measurables
-                .fastFirst { it.layoutId == LayoutId.ShadeHeader }
-                .measure(constraintsWithCutout)
+                .fastFirstOrNull { it.layoutId == LayoutId.ShadeHeader }
+                ?.measure(constraintsWithCutout)
         val mediaPlaceable =
             measurables
                 .fastFirstOrNull { it.layoutId == LayoutId.Media }
                 ?.measure(applyMediaConstraints(constraintsWithCutout, isMediaInRow))
         val quickSettingsPlaceable =
             measurables
-                .fastFirst { it.layoutId == LayoutId.QuickSettings }
-                .measure(constraintsWithCutout)
+                .fastFirstOrNull { it.layoutId == LayoutId.QuickSettings }
+                ?.measure(constraintsWithCutout)
         val notificationsPlaceable =
-            measurables.fastFirst { it.layoutId == LayoutId.Notifications }.measure(constraints)
+            measurables
+                .fastFirstOrNull { it.layoutId == LayoutId.Notifications }
+                ?.measure(constraints)
 
         val notificationsTop =
             calculateNotificationsTop(
@@ -84,23 +85,25 @@
         onNotificationsTopChanged(notificationsTop)
 
         return layout(constraints.maxWidth, constraints.maxHeight) {
-            shadeHeaderPlaceable.placeRelative(x = insetsLeft, y = insetsTop)
-            quickSettingsPlaceable.placeRelative(
+            shadeHeaderPlaceable?.placeRelative(x = insetsLeft, y = insetsTop)
+            val statusBarHeaderHeight = shadeHeaderPlaceable?.height ?: 0
+            quickSettingsPlaceable?.placeRelative(
                 x = insetsLeft,
-                y = insetsTop + shadeHeaderPlaceable.height,
+                y = insetsTop + statusBarHeaderHeight,
             )
 
-            if (mediaPlaceable != null)
+            if (mediaPlaceable != null) {
+                val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
+
                 if (isMediaInRow) {
                     // mediaPlaceable height ranges from 0 to qsHeight. We want it to be centered
                     // vertically when it's smaller than the QS
-                    val mediaCenteringOffset =
-                        (quickSettingsPlaceable.height - mediaPlaceable.height) / 2
+                    val mediaCenteringOffset = (quickSettingsHeight - mediaPlaceable.height) / 2
                     mediaPlaceable.placeRelative(
                         x = insetsLeft + constraintsWithCutout.maxWidth / 2,
                         y =
                             insetsTop +
-                                shadeHeaderPlaceable.height +
+                                statusBarHeaderHeight +
                                 mediaCenteringOffset +
                                 mediaOffset(),
                         zIndex = mediaZIndex(),
@@ -108,30 +111,34 @@
                 } else {
                     mediaPlaceable.placeRelative(
                         x = insetsLeft,
-                        y = insetsTop + shadeHeaderPlaceable.height + quickSettingsPlaceable.height,
+                        y = insetsTop + statusBarHeaderHeight + quickSettingsHeight,
                         zIndex = mediaZIndex(),
                     )
                 }
+            }
 
             // Notifications don't need to accommodate for horizontal insets
-            notificationsPlaceable.placeRelative(x = 0, y = notificationsTop)
+            notificationsPlaceable?.placeRelative(x = 0, y = notificationsTop)
         }
     }
 
     private fun calculateNotificationsTop(
-        statusBarHeaderPlaceable: Placeable,
-        quickSettingsPlaceable: Placeable,
+        statusBarHeaderPlaceable: Placeable?,
+        quickSettingsPlaceable: Placeable?,
         mediaPlaceable: Placeable?,
         insetsTop: Int,
         isMediaInRow: Boolean,
     ): Int {
         val mediaHeight = mediaPlaceable?.height ?: 0
+        val statusBarHeaderHeight = statusBarHeaderPlaceable?.height ?: 0
+        val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
+
         return insetsTop +
-            statusBarHeaderPlaceable.height +
+            statusBarHeaderHeight +
             if (isMediaInRow) {
-                max(quickSettingsPlaceable.height, mediaHeight)
+                max(quickSettingsHeight, mediaHeight)
             } else {
-                quickSettingsPlaceable.height + mediaHeight
+                quickSettingsHeight + mediaHeight
             }
     }
 
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/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 44f60cb..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
@@ -350,8 +350,7 @@
             val placeInThisContent =
                 elementContentWhenIdle(
                     layoutImpl,
-                    currentState.currentScene,
-                    currentState.currentOverlays,
+                    currentState,
                     isInContent = { it in element.stateByContent },
                 ) == content.key
 
@@ -639,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
     }
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/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 1603267..0db545f 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -519,8 +519,19 @@
                 // we intercept an ongoing swipe transition (i.e. startDragImmediately() returned
                 // true).
                 if (overSlop == 0f) {
-                    val delta = (drag.position - consumablePointer.position).toFloat()
-                    check(delta != 0f) { "delta is equal to 0" }
+                    // If the user drags in the opposite direction, the delta becomes zero because
+                    // we return to the original point. Therefore, we should use the previous event
+                    // to calculate the direction.
+                    val delta = (drag.position - drag.previousPosition).toFloat()
+                    check(delta != 0f) {
+                        buildString {
+                            append("delta is equal to 0 ")
+                            append("touchSlop ${currentValueOf(LocalViewConfiguration).touchSlop} ")
+                            append("consumablePointer.position ${consumablePointer.position} ")
+                            append("drag.position ${drag.position} ")
+                            append("drag.previousPosition ${drag.previousPosition}")
+                        }
+                    }
                     overSlop = delta.sign
                 }
                 drag
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/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 7eb5a3f..b3fd097 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
@@ -267,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
@@ -353,8 +354,15 @@
     }
 
     override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
+        Log.i(TAG, "startTransition(transition=$transition, chain=$chain)")
         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)
@@ -366,7 +374,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
@@ -394,7 +402,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].
@@ -477,6 +487,7 @@
             return
         }
 
+        Log.i(TAG, "finishTransition(transition=$transition)")
         check(transitionStates.fastAll { it is TransitionState.Transition })
 
         // Mark this transition as finished.
@@ -504,13 +515,10 @@
         // If all transitions are finished, we are idle.
         if (i == nStates) {
             check(finishedTransitions.isEmpty())
-            this.transitionStates =
-                listOf(
-                    TransitionState.Idle(
-                        lastTransition.currentScene,
-                        lastTransition.currentOverlays,
-                    )
-                )
+            val idle =
+                TransitionState.Idle(lastTransition.currentScene, lastTransition.currentOverlays)
+            Log.i(TAG, "all transitions finished. idle=$idle")
+            this.transitionStates = listOf(idle)
         } else if (i > 0) {
             this.transitionStates = transitionStates.subList(fromIndex = i, toIndex = nStates)
         }
@@ -692,22 +700,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)
                     }
                 }
             }
@@ -722,10 +731,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 569593c..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,17 +26,9 @@
 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.CustomAlphaTransformation
-import com.android.compose.animation.scene.transformation.CustomOffsetTransformation
-import com.android.compose.animation.scene.transformation.CustomScaleTransformation
-import com.android.compose.animation.scene.transformation.CustomSizeTransformation
-import com.android.compose.animation.scene.transformation.InterpolatedAlphaTransformation
-import com.android.compose.animation.scene.transformation.InterpolatedOffsetTransformation
-import com.android.compose.animation.scene.transformation.InterpolatedScaleTransformation
-import com.android.compose.animation.scene.transformation.InterpolatedSizeTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformation
 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
 
 /** The transitions configuration of a [SceneTransitionLayout]. */
@@ -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,46 +345,55 @@
         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 InterpolatedOffsetTransformation,
-                is CustomOffsetTransformation -> {
+
+            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 InterpolatedSizeTransformation,
-                is CustomSizeTransformation -> {
+                is PropertyTransformation.Property.Size -> {
                     throwIfNotNull(size, element, name = "size")
                     size =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<IntSize>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<IntSize>,
+                            transformationMatcher.range,
+                        )
                 }
-                is InterpolatedScaleTransformation,
-                is CustomScaleTransformation -> {
+                is PropertyTransformation.Property.Scale -> {
                     throwIfNotNull(drawScale, element, name = "drawScale")
                     drawScale =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<Scale>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<Scale>,
+                            transformationMatcher.range,
+                        )
                 }
-                is InterpolatedAlphaTransformation,
-                is CustomAlphaTransformation -> {
+                is PropertyTransformation.Property.Alpha -> {
                     throwIfNotNull(alpha, element, name = "alpha")
                     alpha =
-                        transformationWithRange
-                            as TransformationWithRange<PropertyTransformation<Float>>
+                        TransformationWithRange(
+                            transformation as PropertyTransformation<Float>,
+                            transformationMatcher.range,
+                        )
                 }
             }
         }
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/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index 1fdfca9..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,7 +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.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.Transformation
 import kotlin.math.tanh
 
 /** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
@@ -76,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
@@ -102,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
@@ -115,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 {
@@ -529,15 +529,8 @@
         anchorHeight: Boolean = true,
     )
 
-    /**
-     * Apply a [CustomPropertyTransformation] to one or more elements.
-     *
-     * @see com.android.compose.animation.scene.transformation.CustomSizeTransformation
-     * @see com.android.compose.animation.scene.transformation.CustomOffsetTransformation
-     * @see com.android.compose.animation.scene.transformation.CustomAlphaTransformation
-     * @see com.android.compose.animation.scene.transformation.CustomScaleTransformation
-     */
-    fun transformation(transformation: CustomPropertyTransformation<*>)
+    /** 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 79f8cd4..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
@@ -30,7 +30,6 @@
 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.CustomPropertyTransformation
 import com.android.compose.animation.scene.transformation.DrawScale
 import com.android.compose.animation.scene.transformation.EdgeTranslate
 import com.android.compose.animation.scene.transformation.Fade
@@ -38,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 {
@@ -67,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(
@@ -78,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(
@@ -113,7 +112,7 @@
                         progressSpec = snap(),
                         swipeSpec = null,
                         distance = impl.distance,
-                        transformations = impl.transformations,
+                        transformationMatchers = impl.transformationMatchers,
                     ),
                 progressConverter = impl.progressConverter,
             )
@@ -138,7 +137,7 @@
                 progressSpec = impl.spec,
                 swipeSpec = impl.swipeSpec,
                 distance = impl.distance,
-                transformations = impl.transformations,
+                transformationMatchers = impl.transformationMatchers,
             )
         }
 
@@ -158,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
@@ -174,23 +173,31 @@
         range = null
     }
 
-    protected fun addTransformation(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) {
-        addTransformation(Fade(matcher))
+        addTransformation(matcher, Fade.Factory)
     }
 
     override fun translate(matcher: ElementMatcher, x: Dp, y: Dp) {
-        addTransformation(Translate(matcher, x, y))
+        addTransformation(matcher, Translate.Factory(x, y))
     }
 
     override fun translate(
@@ -198,19 +205,19 @@
         edge: Edge,
         startsOutsideLayoutBounds: Boolean,
     ) {
-        addTransformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds))
+        addTransformation(matcher, EdgeTranslate.Factory(edge, startsOutsideLayoutBounds))
     }
 
     override fun anchoredTranslate(matcher: ElementMatcher, anchor: ElementKey) {
-        addTransformation(AnchoredTranslate(matcher, anchor))
+        addTransformation(matcher, AnchoredTranslate.Factory(anchor))
     }
 
     override fun scaleSize(matcher: ElementMatcher, width: Float, height: Float) {
-        addTransformation(ScaleSize(matcher, width, height))
+        addTransformation(matcher, ScaleSize.Factory(width, height))
     }
 
     override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) {
-        addTransformation(DrawScale(matcher, scaleX, scaleY, pivot))
+        addTransformation(matcher, DrawScale.Factory(scaleX, scaleY, pivot))
     }
 
     override fun anchoredSize(
@@ -219,12 +226,12 @@
         anchorWidth: Boolean,
         anchorHeight: Boolean,
     ) {
-        addTransformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
+        addTransformation(matcher, AnchoredSize.Factory(anchor, anchorWidth, anchorHeight))
     }
 
-    override fun transformation(transformation: CustomPropertyTransformation<*>) {
+    override fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory) {
         check(range == null) { "Custom transformations can not be applied inside a range" }
-        addTransformation(transformation)
+        addTransformation(matcher, transformation)
     }
 }
 
@@ -263,7 +270,10 @@
                 "(${transition.toContent.debugName})"
         }
 
-        addTransformation(SharedElementTransformation(matcher, enabled, elevateInContent))
+        addTransformation(
+            matcher,
+            SharedElementTransformation.Factory(matcher, enabled, elevateInContent),
+        )
     }
 
     override fun timestampRange(
@@ -294,6 +304,6 @@
         x: OverscrollScope.() -> Float,
         y: OverscrollScope.() -> Float,
     ) {
-        addTransformation(OverscrollTranslate(matcher, x, y))
+        addTransformation(matcher, OverscrollTranslate.Factory(x, y))
     }
 }
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 38b1aaa..d66fe42 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
@@ -90,6 +90,10 @@
                     // The set of overlays does not change in a [ChangeCurrentScene] transition.
                     return currentOverlaysWhenTransitionStarted
                 }
+
+            override fun toString(): String {
+                return "ChangeScene(fromScene=$fromScene, toScene=$toScene)"
+            }
         }
 
         /**
@@ -146,6 +150,12 @@
                     currentOverlaysWhenTransitionStarted - overlay
                 }
             }
+
+            override fun toString(): String {
+                val isShowing = overlay == toContent
+                return "ShowOrHideOverlay(overlay=$overlay, fromOrToScene=$fromOrToScene, " +
+                    "isShowing=$isShowing)"
+            }
         }
 
         /** We are transitioning from [fromOverlay] to [toOverlay]. */
@@ -194,6 +204,10 @@
                     add(include)
                 }
             }
+
+            override fun toString(): String {
+                return "ReplaceOverlay(fromOverlay=$fromOverlay, toOverlay=$toOverlay)"
+            }
         }
 
         /**
@@ -401,7 +415,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 85bb533..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,
-) : InterpolatedSizeTransformation {
+) : 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 04cd683..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,
-) : InterpolatedOffsetTransformation {
+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 45d6d40..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,
-) : InterpolatedScaleTransformation {
+    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 21d66d7..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,
-) : InterpolatedOffsetTransformation {
+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 d942273..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) : InterpolatedAlphaTransformation {
+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 5f3cdab..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,
-) : InterpolatedSizeTransformation {
+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 d5143d7..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
@@ -35,26 +35,59 @@
 
 /** 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
+    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. */
-sealed 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.
  */
-sealed interface InterpolatedPropertyTransformation<T> : PropertyTransformation<T> {
+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
@@ -73,19 +106,7 @@
     ): T
 }
 
-/** An [InterpolatedPropertyTransformation] applied to the size of one or more elements. */
-interface InterpolatedSizeTransformation : InterpolatedPropertyTransformation<IntSize>
-
-/** An [InterpolatedPropertyTransformation] applied to the offset of one or more elements. */
-interface InterpolatedOffsetTransformation : InterpolatedPropertyTransformation<Offset>
-
-/** An [InterpolatedPropertyTransformation] applied to the alpha of one or more elements. */
-interface InterpolatedAlphaTransformation : InterpolatedPropertyTransformation<Float>
-
-/** An [InterpolatedPropertyTransformation] applied to the scale of one or more elements. */
-interface InterpolatedScaleTransformation : InterpolatedPropertyTransformation<Scale>
-
-sealed interface CustomPropertyTransformation<T> : PropertyTransformation<T> {
+interface CustomPropertyTransformation<T> : PropertyTransformation<T> {
     /**
      * Return the value that the property should have in the current frame for the given [content]
      * and [element].
@@ -105,25 +126,20 @@
     ): T
 }
 
-/** A [CustomPropertyTransformation] applied to the size of one or more elements. */
-interface CustomSizeTransformation : CustomPropertyTransformation<IntSize>
-
-/** A [CustomPropertyTransformation] applied to the offset of one or more elements. */
-interface CustomOffsetTransformation : CustomPropertyTransformation<Offset>
-
-/** A [CustomPropertyTransformation] applied to the alpha of one or more elements. */
-interface CustomAlphaTransformation : CustomPropertyTransformation<Float>
-
-/** A [CustomPropertyTransformation] applied to the scale of one or more elements. */
-interface CustomScaleTransformation : CustomPropertyTransformation<Scale>
-
 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?,
 ) {
@@ -135,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,
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 d756c86..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,
-) : InterpolatedOffsetTransformation {
+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 },
-) : InterpolatedOffsetTransformation {
+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/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 61e9bb0..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
@@ -644,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)
@@ -1530,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/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 5ec74f8..85d8b60 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -593,7 +593,7 @@
             }
         }
 
-        fun continueDraggingDown() {
+        fun dragDown() {
             rule.onRoot().performTouchInput { moveBy(Offset(0f, touchSlop)) }
         }
 
@@ -603,11 +603,78 @@
         assertThat(started).isFalse()
 
         swipeConsume = true
-        continueDraggingDown()
+        // Drag in same direction
+        dragDown()
         assertThat(capturedChange).isNotNull()
         capturedChange = null
 
-        continueDraggingDown()
+        dragDown()
+        assertThat(capturedChange).isNull()
+
+        assertThat(started).isTrue()
+    }
+
+    @Test
+    fun multiPointerSwipeDetectorInteractionZeroOffsetFromStartPosition() {
+        val size = 200f
+        val middle = Offset(size / 2f, size / 2f)
+
+        var started = false
+
+        var capturedChange: PointerInputChange? = null
+        var swipeConsume = false
+
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            Box(
+                Modifier.size(with(LocalDensity.current) { Size(size, size).toDpSize() })
+                    .nestedScrollDispatcher()
+                    .multiPointerDraggable(
+                        orientation = Orientation.Vertical,
+                        startDragImmediately = { false },
+                        swipeDetector =
+                            object : SwipeDetector {
+                                override fun detectSwipe(change: PointerInputChange): Boolean {
+                                    capturedChange = change
+                                    return swipeConsume
+                                }
+                            },
+                        onDragStarted = { _, _ ->
+                            started = true
+                            SimpleDragController(
+                                onDrag = { /* do nothing */ },
+                                onStop = { /* do nothing */ },
+                            )
+                        },
+                        dispatcher = defaultDispatcher,
+                    )
+            ) {}
+        }
+
+        fun startDraggingDown() {
+            rule.onRoot().performTouchInput {
+                down(middle)
+                moveBy(Offset(0f, touchSlop))
+            }
+        }
+
+        fun dragUp() {
+            rule.onRoot().performTouchInput { moveBy(Offset(0f, -touchSlop)) }
+        }
+
+        startDraggingDown()
+        assertThat(capturedChange).isNotNull()
+        capturedChange = null
+        assertThat(started).isFalse()
+
+        swipeConsume = true
+        // Drag in the opposite direction
+        dragUp()
+        assertThat(capturedChange).isNotNull()
+        capturedChange = null
+
+        dragUp()
         assertThat(capturedChange).isNull()
 
         assertThat(started).isTrue()
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 57ad81e..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
@@ -153,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)
@@ -166,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
@@ -686,4 +686,30 @@
         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 1f9ba9e..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
@@ -28,11 +28,12 @@
 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.CustomSizeTransformation
+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
@@ -103,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)
     }
@@ -126,7 +127,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -157,7 +158,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -185,7 +186,7 @@
         }
 
         val transformations =
-            transitions.transitionSpecs.single().transformationSpec(aToB()).transformations
+            transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
             .containsExactly(
@@ -215,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)
@@ -225,7 +226,7 @@
             )
 
         val previewTransformations =
-            transitionSpec.previewTransformationSpec(aToB())?.transformations
+            transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
 
         assertThat(previewTransformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -255,7 +256,7 @@
                 key = TransitionKey.PredictiveBack,
             )
 
-        val transformations = transitionSpec.transformationSpec(aToB()).transformations
+        val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers
 
         assertThat(transformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -265,7 +266,7 @@
             )
 
         val previewTransformations =
-            transitionSpec.previewTransformationSpec(aToB())?.transformations
+            transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers
 
         assertThat(previewTransformations)
             .comparingElementsUsing(TRANSFORMATION_RANGE)
@@ -316,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)
     }
 
@@ -324,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
@@ -353,9 +354,9 @@
         val transitions = transitions {
             from(SceneA, to = SceneB) {
                 fractionRange {
-                    transformation(
-                        object : CustomSizeTransformation {
-                            override val matcher: ElementMatcher = TestElements.Foo
+                    transformation(TestElements.Foo) {
+                        object : CustomPropertyTransformation<IntSize> {
+                            override val property = PropertyTransformation.Property.Size
 
                             override fun PropertyTransformationScope.transform(
                                 content: ContentKey,
@@ -364,7 +365,7 @@
                                 transitionScope: CoroutineScope,
                             ): IntSize = IntSize.Zero
                         }
-                    )
+                    }
                 }
             }
         }
@@ -377,7 +378,7 @@
 
     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
index 487b099..444ec4e 100644
--- 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
@@ -30,7 +30,6 @@
 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.ElementMatcher
 import com.android.compose.animation.scene.TestElements
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.testTransition
@@ -47,8 +46,9 @@
     @Test
     fun customSize() {
         /** A size transformation that adds [add] to the size of the transformed element(s). */
-        class AddSizeTransformation(override val matcher: ElementMatcher, private val add: Dp) :
-            CustomSizeTransformation {
+        class AddSizeTransformation(private val add: Dp) : CustomPropertyTransformation<IntSize> {
+            override val property = PropertyTransformation.Property.Size
+
             override fun PropertyTransformationScope.transform(
                 content: ContentKey,
                 element: ElementKey,
@@ -69,7 +69,7 @@
                 spec = tween(16 * 4, easing = LinearEasing)
 
                 // Add 80dp to the width and height of Foo.
-                transformation(AddSizeTransformation(TestElements.Foo, 80.dp))
+                transformation(TestElements.Foo) { AddSizeTransformation(80.dp) }
             },
         ) {
             before { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) }
@@ -84,8 +84,9 @@
     @Test
     fun customOffset() {
         /** An offset transformation that adds [add] to the offset of the transformed element(s). */
-        class AddOffsetTransformation(override val matcher: ElementMatcher, private val add: Dp) :
-            CustomOffsetTransformation {
+        class AddOffsetTransformation(private val add: Dp) : CustomPropertyTransformation<Offset> {
+            override val property = PropertyTransformation.Property.Offset
+
             override fun PropertyTransformationScope.transform(
                 content: ContentKey,
                 element: ElementKey,
@@ -106,7 +107,7 @@
                 spec = tween(16 * 4, easing = LinearEasing)
 
                 // Add 80dp to the offset of Foo.
-                transformation(AddOffsetTransformation(TestElements.Foo, 80.dp))
+                transformation(TestElements.Foo) { AddOffsetTransformation(80.dp) }
             },
         ) {
             before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) }
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/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 935737c..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
@@ -67,11 +67,7 @@
             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) {
-                    // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
-                    return@TypefaceCache Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
-                }
+            val typefaceCache = TypefaceCache(buffers.infraMessageBuffer) { FLEX_TYPEFACE }
             FlexClockController(
                 ClockContext(
                     ctx,
@@ -131,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(
@@ -154,7 +155,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "hh",
                                 ),
@@ -173,7 +174,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "hh",
                                 ),
@@ -192,7 +193,7 @@
                                     alignment =
                                         DigitalAlignment(
                                             HorizontalAlignment.CENTER,
-                                            VerticalAlignment.CENTER,
+                                            VerticalAlignment.BASELINE,
                                         ),
                                     dateTimeFormat = "mm",
                                 ),
@@ -211,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/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index 27ed099..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
@@ -18,6 +18,7 @@
 
 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
@@ -26,6 +27,7 @@
 import com.android.systemui.customization.R
 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
@@ -34,10 +36,14 @@
 
 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)
@@ -46,6 +52,7 @@
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
             )
+        updateLocale(Locale.getDefault())
     }
 
     private val digitOffsets = mutableMapOf<Int, Float>()
@@ -58,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),
@@ -103,6 +117,11 @@
         }
     }
 
+    override fun onLocaleChanged(locale: Locale) {
+        updateLocale(locale)
+        requestLayout()
+    }
+
     override fun animateDoze(isDozing: Boolean, isAnimated: Boolean) {
         dozeControlState.animateDoze = {
             super.animateDoze(isDozing, isAnimated)
@@ -163,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.
      *
@@ -261,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 bd56dbf..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
@@ -101,7 +101,7 @@
         }
     }
 
-    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
@@ -242,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()
@@ -387,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)
@@ -413,7 +413,9 @@
                         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()
             }
         }
 
@@ -533,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/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/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
index 7cdfb0e..0f148f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelTest.kt
@@ -30,11 +30,11 @@
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
-import com.android.systemui.kosmos.brightnessWarningToast
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.lifecycle.activateIn
 import com.android.systemui.res.R
 import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
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 6b851cb..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,
             )
     }
 
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/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
index f0d79bb..47cba07 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorTest.kt
@@ -568,6 +568,41 @@
             assertThat(isUnlocked).isFalse()
         }
 
+    @Test
+    fun lockNow() =
+        testScope.runTest {
+            setLockAfterScreenTimeout(5000)
+            val isUnlocked by collectLastValue(underTest.deviceUnlockStatus.map { it.isUnlocked })
+            unlockDevice()
+            assertThat(isUnlocked).isTrue()
+
+            underTest.lockNow()
+            runCurrent()
+
+            assertThat(isUnlocked).isFalse()
+        }
+
+    @Test
+    fun deviceUnlockStatus_isResetToFalse_whenDeviceGoesToSleep_fromSleepButton() =
+        testScope.runTest {
+            setLockAfterScreenTimeout(5000)
+            kosmos.fakeAuthenticationRepository.powerButtonInstantlyLocks = false
+            val deviceUnlockStatus by collectLastValue(underTest.deviceUnlockStatus)
+
+            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+                SuccessFingerprintAuthenticationStatus(0, true)
+            )
+            runCurrent()
+            assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+
+            kosmos.powerInteractor.setAsleepForTest(
+                sleepReason = PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON
+            )
+            runCurrent()
+
+            assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+        }
+
     private fun TestScope.unlockDevice() {
         val deviceUnlockStatus by collectLastValue(underTest.deviceUnlockStatus)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt
new file mode 100644
index 0000000..7891787
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt
@@ -0,0 +1,181 @@
+/*
+ * 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.display.domain.interactor
+
+import android.hardware.display.defaultDisplay
+import android.hardware.display.rearDisplay
+import android.view.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.DeviceStateRepository
+import com.android.systemui.display.data.repository.FakeDeviceStateRepository
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.whenever
+
+/** atest RearDisplayStateInteractorTest */
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class RearDisplayStateInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val fakeDisplayRepository = FakeDisplayRepository()
+    private val fakeDeviceStateRepository = FakeDeviceStateRepository()
+    private val rearDisplayStateInteractor =
+        RearDisplayStateInteractorImpl(
+            fakeDisplayRepository,
+            fakeDeviceStateRepository,
+            kosmos.testDispatcher,
+        )
+    private val emissionTracker = EmissionTracker(rearDisplayStateInteractor, kosmos.testScope)
+
+    @Before
+    fun setup() {
+        whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR)
+    }
+
+    @Test
+    fun enableRearDisplayWhenDisplayImmediatelyAvailable() =
+        kosmos.runTest {
+            emissionTracker.use { tracker ->
+                fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(0)
+                fakeDeviceStateRepository.emit(
+                    DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+                )
+
+                assertThat(tracker.enabledCount).isEqualTo(1)
+                assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay)
+            }
+        }
+
+    @Test
+    fun enableAndDisableRearDisplay() =
+        kosmos.runTest {
+            emissionTracker.use { tracker ->
+                // The fake FakeDeviceStateRepository will always start with state UNKNOWN, thus
+                // triggering one initial emission
+                assertThat(tracker.disabledCount).isEqualTo(1)
+
+                fakeDeviceStateRepository.emit(
+                    DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+                )
+
+                // Adding a non-rear display does not trigger an emission
+                fakeDisplayRepository.addDisplay(kosmos.defaultDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(0)
+
+                // Adding a rear display triggers the emission
+                fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(1)
+                assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay)
+
+                fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+                assertThat(tracker.disabledCount).isEqualTo(2)
+            }
+        }
+
+    @Test
+    fun enableRearDisplayShouldOnlyReactToFirstRearDisplay() =
+        kosmos.runTest {
+            emissionTracker.use { tracker ->
+                fakeDeviceStateRepository.emit(
+                    DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+                )
+
+                // Adding a rear display triggers the emission
+                fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(1)
+
+                // Adding additional rear displays does not trigger additional emissions
+                fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(1)
+            }
+        }
+
+    @Test
+    fun rearDisplayAddedWhenNoLongerInRdm() =
+        kosmos.runTest {
+            emissionTracker.use { tracker ->
+                fakeDeviceStateRepository.emit(
+                    DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+                )
+                fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+
+                // Adding a rear display when no longer in the correct device state does not trigger
+                // an emission
+                fakeDisplayRepository.addDisplay(kosmos.rearDisplay)
+                assertThat(tracker.enabledCount).isEqualTo(0)
+            }
+        }
+
+    @Test
+    fun rearDisplayDisabledDoesNotSpam() =
+        kosmos.runTest {
+            emissionTracker.use { tracker ->
+                fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED)
+                assertThat(tracker.disabledCount).isEqualTo(1)
+
+                // No additional emission
+                fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.FOLDED)
+                assertThat(tracker.disabledCount).isEqualTo(1)
+            }
+        }
+
+    class EmissionTracker(rearDisplayInteractor: RearDisplayStateInteractor, scope: TestScope) :
+        AutoCloseable {
+        var enabledCount = 0
+        var disabledCount = 0
+        var lastDisplay: Display? = null
+
+        val job: Job
+
+        init {
+            val channel = Channel<RearDisplayStateInteractor.State>(Channel.UNLIMITED)
+            job =
+                scope.launch {
+                    rearDisplayInteractor.state.collect {
+                        channel.send(it)
+                        if (it is RearDisplayStateInteractor.State.Enabled) {
+                            enabledCount++
+                            lastDisplay = it.innerDisplay
+                        }
+                        if (it is RearDisplayStateInteractor.State.Disabled) {
+                            disabledCount++
+                        }
+                    }
+                }
+        }
+
+        override fun close() {
+            job.cancel()
+        }
+    }
+}
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 cc4c7c4..27b8c59 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
@@ -18,13 +18,17 @@
 
 import android.content.Context
 import android.content.Context.INPUT_SERVICE
-import android.hardware.input.InputGestureData
-import android.hardware.input.InputGestureData.createKeyTrigger
-import android.hardware.input.KeyGestureEvent
 import android.hardware.input.fakeInputManager
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
-import android.view.KeyEvent
+import android.view.KeyEvent.KEYCODE_SLASH
+import android.view.KeyEvent.META_ALT_ON
+import android.view.KeyEvent.META_CAPS_LOCK_ON
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_FUNCTION_ON
+import android.view.KeyEvent.META_META_ON
+import android.view.KeyEvent.META_SHIFT_ON
+import android.view.KeyEvent.META_SYM_ON
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.hardware.input.Flags.FLAG_ENABLE_CUSTOMIZABLE_INPUT_GESTURES
@@ -32,17 +36,14 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyboard.shortcut.customShortcutCategoriesRepository
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.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.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customizableInputGestureWithUnknownKeyGestureType
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.expectedShortcutCategoriesWithSimpleShortcutCombination
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
 import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.settings.userTracker
 import com.android.systemui.testKosmos
@@ -83,7 +84,7 @@
             whenever(
                     fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
                 )
-                .thenReturn(customizableInputGesturesWithSimpleShortcutCombinations)
+                .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
 
             helper.toggle(deviceId = 123)
             val categories by collectLastValue(repo.categories)
@@ -100,7 +101,7 @@
             whenever(
                     fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())
                 )
-                .thenReturn(customizableInputGesturesWithSimpleShortcutCombinations)
+                .thenReturn(allCustomizableInputGesturesWithSimpleShortcutCombinations)
 
             helper.toggle(deviceId = 123)
             val categories by collectLastValue(repo.categories)
@@ -125,167 +126,73 @@
         }
     }
 
-    private fun simpleInputGestureData(
-        keyCode: Int = KeyEvent.KEYCODE_A,
-        modifiers: Int = KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
-        keyGestureType: Int,
-    ): InputGestureData {
-        val builder = InputGestureData.Builder()
-        builder.setKeyGestureType(keyGestureType)
-        builder.setTrigger(createKeyTrigger(keyCode, modifiers))
-        return builder.build()
+    @Test
+    fun pressedKeys_isEmptyByDefault() {
+        testScope.runTest {
+            val pressedKeys by collectLastValue(repo.pressedKeys)
+            assertThat(pressedKeys).isEmpty()
+
+            helper.toggle(deviceId = 123)
+            assertThat(pressedKeys).isEmpty()
+        }
     }
 
-    private fun simpleShortcutCategory(
-        category: ShortcutCategoryType,
-        subcategoryLabel: String,
-        shortcutLabel: String,
-    ): ShortcutCategory {
-        return ShortcutCategory(
-            type = category,
-            subCategories =
-                listOf(
-                    ShortcutSubCategory(
-                        label = subcategoryLabel,
-                        shortcuts = listOf(simpleShortcut(shortcutLabel)),
-                    )
-                ),
-        )
+    @Test
+    fun pressedKeys_recognizesAllSupportedModifiers() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            val pressedKeys by collectLastValue(repo.pressedKeys)
+            repo.updateUserKeyCombination(
+                KeyCombination(modifiers = allSupportedModifiers, keyCode = null)
+            )
+
+            assertThat(pressedKeys)
+                .containsExactly(
+                    ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+                    ShortcutKey.Text("Ctrl"),
+                    ShortcutKey.Text("Fn"),
+                    ShortcutKey.Text("Shift"),
+                    ShortcutKey.Text("Alt"),
+                    ShortcutKey.Text("Sym"),
+                )
+        }
     }
 
-    private fun simpleShortcut(label: String) =
-        Shortcut(
-            label = label,
-            commands =
-                listOf(
-                    ShortcutCommand(
-                        isCustom = true,
-                        keys =
-                            listOf(
-                                ShortcutKey.Text("Ctrl"),
-                                ShortcutKey.Text("Alt"),
-                                ShortcutKey.Text("A"),
-                            ),
-                    )
-                ),
-        )
+    @Test
+    fun pressedKeys_ignoresUnsupportedModifiers() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            val pressedKeys by collectLastValue(repo.pressedKeys)
+            repo.updateUserKeyCombination(
+                KeyCombination(modifiers = META_CAPS_LOCK_ON, keyCode = null)
+            )
 
-    private val customizableInputGestureWithUnknownKeyGestureType =
-        // These key gesture events are currently not supported by shortcut helper customizer
-        listOf(
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY),
-        )
+            assertThat(pressedKeys).isEmpty()
+        }
+    }
 
-    private val expectedShortcutCategoriesWithSimpleShortcutCombination =
-        listOf(
-            simpleShortcutCategory(System, "System apps", "Open assistant"),
-            simpleShortcutCategory(System, "System controls", "Go to home screen"),
-            simpleShortcutCategory(System, "System apps", "Open settings"),
-            simpleShortcutCategory(System, "System controls", "Lock screen"),
-            simpleShortcutCategory(System, "System controls", "View notifications"),
-            simpleShortcutCategory(System, "System apps", "Take a note"),
-            simpleShortcutCategory(System, "System controls", "Take screenshot"),
-            simpleShortcutCategory(System, "System controls", "Go back"),
-            simpleShortcutCategory(
-                MultiTasking,
-                "Split screen",
-                "Switch from split screen to full screen",
-            ),
-            simpleShortcutCategory(
-                MultiTasking,
-                "Split screen",
-                "Use split screen with current app on the left",
-            ),
-            simpleShortcutCategory(
-                MultiTasking,
-                "Split screen",
-                "Switch to app on left or above while using split screen",
-            ),
-            simpleShortcutCategory(
-                MultiTasking,
-                "Split screen",
-                "Use split screen with current app on the right",
-            ),
-            simpleShortcutCategory(
-                MultiTasking,
-                "Split screen",
-                "Switch to app on right or below while using split screen",
-            ),
-            simpleShortcutCategory(System, "System controls", "Show shortcuts"),
-            simpleShortcutCategory(System, "System controls", "View recent apps"),
-            simpleShortcutCategory(AppCategories, "Applications", "Calculator"),
-            simpleShortcutCategory(AppCategories, "Applications", "Calendar"),
-            simpleShortcutCategory(AppCategories, "Applications", "Browser"),
-            simpleShortcutCategory(AppCategories, "Applications", "Contacts"),
-            simpleShortcutCategory(AppCategories, "Applications", "Email"),
-            simpleShortcutCategory(AppCategories, "Applications", "Maps"),
-            simpleShortcutCategory(AppCategories, "Applications", "SMS"),
-            simpleShortcutCategory(MultiTasking, "Recent apps", "Cycle forward through recent apps"),
-        )
+    @Test
+    fun pressedKeys_assertCorrectConversion() {
+        testScope.runTest {
+            helper.toggle(deviceId = 123)
+            val pressedKeys by collectLastValue(repo.pressedKeys)
+            repo.updateUserKeyCombination(
+                KeyCombination(modifiers = META_META_ON, keyCode = KEYCODE_SLASH)
+            )
 
-    private val customizableInputGesturesWithSimpleShortcutCombinations =
-        listOf(
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
-            ),
-            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
-            ),
-            simpleInputGestureData(
-                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
-            ),
-        )
+            assertThat(pressedKeys)
+                .containsExactly(
+                    ShortcutKey.Icon.ResIdIcon(R.drawable.ic_ksh_key_meta),
+                    ShortcutKey.Text("/"),
+                )
+        }
+    }
+
+    private val allSupportedModifiers =
+        META_META_ON or
+            META_CTRL_ON or
+            META_FUNCTION_ON or
+            META_SHIFT_ON or
+            META_ALT_ON or
+            META_SYM_ON
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index c9c39b3..a1e7ef4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -16,11 +16,20 @@
 
 package com.android.systemui.keyboard.shortcut.data.source
 
+import android.hardware.input.InputGestureData
+import android.hardware.input.InputGestureData.createKeyTrigger
+import android.hardware.input.KeyGestureEvent
 import android.view.KeyEvent
 import android.view.KeyboardShortcutGroup
 import android.view.KeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.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.keyboard.shortcut.shared.model.ShortcutCommand
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
 import com.android.systemui.keyboard.shortcut.shared.model.shortcut
 import com.android.systemui.res.R
@@ -64,6 +73,13 @@
             }
         }
 
+    private val goHomeShortcutInfo =
+        KeyboardShortcutInfo(
+            /* label = */ "Go to home screen",
+            /* keycode = */ KeyEvent.KEYCODE_B,
+            /* modifiers = */ KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
+        )
+
     private val standardShortcutInfo1 =
         KeyboardShortcutInfo(
             /* label = */ "Standard shortcut 1",
@@ -79,6 +95,16 @@
             }
         }
 
+    private val customGoHomeShortcut =
+        shortcut("Go to home screen") {
+            command {
+                key("Ctrl")
+                key("Alt")
+                key("A")
+                isCustom(true)
+            }
+        }
+
     private val standardShortcutInfo2 =
         KeyboardShortcutInfo(
             /* label = */ "Standard shortcut 2",
@@ -123,35 +149,38 @@
             listOf(
                 shortcutInfoWithRepeatedLabel,
                 shortcutInfoWithRepeatedLabelAlternate,
-                shortcutInfoWithRepeatedLabelSecondAlternate
-            )
+                shortcutInfoWithRepeatedLabelSecondAlternate,
+            ),
         )
 
     private val subCategoryWithGroupedRepeatedShortcutLabels =
         ShortcutSubCategory(
             label = groupWithRepeatedShortcutLabels.label!!.toString(),
-            shortcuts = listOf(shortcutWithGroupedRepeatedLabel)
+            shortcuts = listOf(shortcutWithGroupedRepeatedLabel),
         )
 
     private val groupWithStandardShortcutInfo =
         KeyboardShortcutGroup("Standard group", listOf(standardShortcutInfo1))
 
+    val groupWithGoHomeShortcutInfo =
+        KeyboardShortcutGroup("System controls", listOf(goHomeShortcutInfo))
+
     private val subCategoryWithStandardShortcut =
         ShortcutSubCategory(
             label = groupWithStandardShortcutInfo.label!!.toString(),
-            shortcuts = listOf(standardShortcut1)
+            shortcuts = listOf(standardShortcut1),
         )
 
     private val groupWithOnlyUnsupportedModifierShortcut =
         KeyboardShortcutGroup(
             "Group with unsupported modifiers",
-            listOf(shortcutInfoWithUnsupportedModifiers)
+            listOf(shortcutInfoWithUnsupportedModifiers),
         )
 
     private val groupWithSupportedAndUnsupportedModifierShortcut =
         KeyboardShortcutGroup(
             "Group with mix of supported and not supported modifiers",
-            listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers)
+            listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers),
         )
 
     private val switchToNextLanguageShortcut =
@@ -174,19 +203,19 @@
     private val subCategoryForInputLanguageSwitchShortcuts =
         ShortcutSubCategory(
             "Input",
-            listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut)
+            listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut),
         )
 
     private val subCategoryWithUnsupportedShortcutsRemoved =
         ShortcutSubCategory(
             groupWithSupportedAndUnsupportedModifierShortcut.label!!.toString(),
-            listOf(standardShortcut3)
+            listOf(standardShortcut3),
         )
 
     private val standardGroup1 =
         KeyboardShortcutGroup(
             "Standard group 1",
-            listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+            listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3),
         )
 
     private val standardPackageName1 = "standard.app.group1"
@@ -194,38 +223,63 @@
     private val standardAppGroup1 =
         KeyboardShortcutGroup(
                 "Standard app group 1",
-                listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+                listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3),
             )
             .apply { packageName = standardPackageName1 }
 
+    private val standardSystemAppSubcategoryWithCustomHomeShortcut =
+        ShortcutSubCategory("System controls", listOf(customGoHomeShortcut))
+
     private val standardSubCategory1 =
         ShortcutSubCategory(
             standardGroup1.label!!.toString(),
-            listOf(standardShortcut1, standardShortcut2, standardShortcut3)
+            listOf(standardShortcut1, standardShortcut2, standardShortcut3),
         )
 
     private val standardGroup2 =
         KeyboardShortcutGroup(
             "Standard group 2",
-            listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1)
+            listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1),
         )
 
     private val standardSubCategory2 =
         ShortcutSubCategory(
             standardGroup2.label!!.toString(),
-            listOf(standardShortcut3, standardShortcut2, standardShortcut1)
+            listOf(standardShortcut3, standardShortcut2, standardShortcut1),
         )
     private val standardGroup3 =
         KeyboardShortcutGroup(
             "Standard group 3",
-            listOf(standardShortcutInfo2, standardShortcutInfo1)
+            listOf(standardShortcutInfo2, standardShortcutInfo1),
         )
 
     private val standardSubCategory3 =
         ShortcutSubCategory(
             standardGroup3.label!!.toString(),
-            listOf(standardShortcut2, standardShortcut1)
+            listOf(standardShortcut2, standardShortcut1),
         )
+
+    private val systemSubCategoryWithGoHomeShortcuts =
+        ShortcutSubCategory(
+            label = "System controls",
+            shortcuts =
+                listOf(
+                    shortcut("Go to home screen") {
+                        command {
+                            key("Ctrl")
+                            key("Alt")
+                            key("B")
+                        }
+                        command {
+                            key("Ctrl")
+                            key("Alt")
+                            key("A")
+                            isCustom(true)
+                        }
+                    }
+                ),
+        )
+
     val imeGroups = listOf(standardGroup1, standardGroup2, standardGroup3)
     val imeCategory =
         ShortcutCategory(
@@ -235,8 +289,8 @@
                     subCategoryForInputLanguageSwitchShortcuts,
                     standardSubCategory1,
                     standardSubCategory2,
-                    standardSubCategory3
-                )
+                    standardSubCategory3,
+                ),
         )
 
     val currentAppGroups = listOf(standardAppGroup1)
@@ -245,15 +299,33 @@
     val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
     val systemCategory =
         ShortcutCategory(
-            type = ShortcutCategoryType.System,
-            subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1)
+            type = System,
+            subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1),
+        )
+
+    val systemCategoryWithMergedGoHomeShortcut =
+        ShortcutCategory(
+            type = System,
+            subCategories = listOf(systemSubCategoryWithGoHomeShortcuts),
+        )
+
+    val systemCategoryWithCustomHomeShortcut =
+        ShortcutCategory(
+            type = System,
+            subCategories =
+                listOf(
+                    standardSubCategory3,
+                    standardSubCategory2,
+                    standardSubCategory1,
+                    standardSystemAppSubcategoryWithCustomHomeShortcut,
+                ),
         )
 
     val multitaskingGroups = listOf(standardGroup2, standardGroup1)
     val multitaskingCategory =
         ShortcutCategory(
-            type = ShortcutCategoryType.MultiTasking,
-            subCategories = listOf(standardSubCategory2, standardSubCategory1)
+            type = MultiTasking,
+            subCategories = listOf(standardSubCategory2, standardSubCategory1),
         )
 
     val groupsWithDuplicateShortcutLabels =
@@ -266,14 +338,14 @@
         listOf(
             subCategoryForInputLanguageSwitchShortcuts,
             subCategoryWithGroupedRepeatedShortcutLabels,
-            subCategoryWithStandardShortcut
+            subCategoryWithStandardShortcut,
         )
 
     val groupsWithUnsupportedModifier =
         listOf(
             groupWithStandardShortcutInfo,
             groupWithOnlyUnsupportedModifierShortcut,
-            groupWithSupportedAndUnsupportedModifierShortcut
+            groupWithSupportedAndUnsupportedModifierShortcut,
         )
 
     val subCategoriesWithUnsupportedModifiersRemoved =
@@ -283,8 +355,174 @@
         listOf(
             subCategoryForInputLanguageSwitchShortcuts,
             subCategoryWithStandardShortcut,
-            subCategoryWithUnsupportedShortcutsRemoved
+            subCategoryWithUnsupportedShortcutsRemoved,
         )
 
     val groupsWithOnlyUnsupportedModifiers = listOf(groupWithOnlyUnsupportedModifierShortcut)
+
+    private fun simpleInputGestureData(
+        keyCode: Int = KeyEvent.KEYCODE_A,
+        modifiers: Int = KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON,
+        keyGestureType: Int,
+    ): InputGestureData {
+        val builder = InputGestureData.Builder()
+        builder.setKeyGestureType(keyGestureType)
+        builder.setTrigger(createKeyTrigger(keyCode, modifiers))
+        return builder.build()
+    }
+
+    private fun simpleShortcutCategory(
+        category: ShortcutCategoryType,
+        subcategoryLabel: String,
+        shortcutLabel: String,
+    ): ShortcutCategory {
+        return ShortcutCategory(
+            type = category,
+            subCategories =
+                listOf(
+                    ShortcutSubCategory(
+                        label = subcategoryLabel,
+                        shortcuts = listOf(simpleShortcut(shortcutLabel)),
+                    )
+                ),
+        )
+    }
+
+    private fun simpleShortcut(label: String) =
+        Shortcut(
+            label = label,
+            commands =
+                listOf(
+                    ShortcutCommand(
+                        isCustom = true,
+                        keys =
+                            listOf(
+                                ShortcutKey.Text("Ctrl"),
+                                ShortcutKey.Text("Alt"),
+                                ShortcutKey.Text("A"),
+                            ),
+                    )
+                ),
+        )
+
+    val customizableInputGestureWithUnknownKeyGestureType =
+        // These key gesture events are currently not supported by shortcut helper customizer
+        listOf(
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MEDIA_KEY),
+        )
+
+    val expectedShortcutCategoriesWithSimpleShortcutCombination =
+        listOf(
+            simpleShortcutCategory(System, "System apps", "Open assistant"),
+            simpleShortcutCategory(System, "System controls", "Go to home screen"),
+            simpleShortcutCategory(System, "System apps", "Open settings"),
+            simpleShortcutCategory(System, "System controls", "Lock screen"),
+            simpleShortcutCategory(System, "System controls", "View notifications"),
+            simpleShortcutCategory(System, "System apps", "Take a note"),
+            simpleShortcutCategory(System, "System controls", "Take screenshot"),
+            simpleShortcutCategory(System, "System controls", "Go back"),
+            simpleShortcutCategory(
+                MultiTasking,
+                "Split screen",
+                "Switch from split screen to full screen",
+            ),
+            simpleShortcutCategory(
+                MultiTasking,
+                "Split screen",
+                "Use split screen with current app on the left",
+            ),
+            simpleShortcutCategory(
+                MultiTasking,
+                "Split screen",
+                "Switch to app on left or above while using split screen",
+            ),
+            simpleShortcutCategory(
+                MultiTasking,
+                "Split screen",
+                "Use split screen with current app on the right",
+            ),
+            simpleShortcutCategory(
+                MultiTasking,
+                "Split screen",
+                "Switch to app on right or below while using split screen",
+            ),
+            simpleShortcutCategory(System, "System controls", "Show shortcuts"),
+            simpleShortcutCategory(System, "System controls", "View recent apps"),
+            simpleShortcutCategory(AppCategories, "Applications", "Calculator"),
+            simpleShortcutCategory(AppCategories, "Applications", "Calendar"),
+            simpleShortcutCategory(AppCategories, "Applications", "Browser"),
+            simpleShortcutCategory(AppCategories, "Applications", "Contacts"),
+            simpleShortcutCategory(AppCategories, "Applications", "Email"),
+            simpleShortcutCategory(AppCategories, "Applications", "Maps"),
+            simpleShortcutCategory(AppCategories, "Applications", "SMS"),
+            simpleShortcutCategory(MultiTasking, "Recent apps", "Cycle forward through recent apps"),
+        )
+    val customInputGestureTypeHome =
+        simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+
+    val allCustomizableInputGesturesWithSimpleShortcutCombinations =
+        listOf(
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_HOME),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_BACK),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER
+            ),
+            simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING
+            ),
+            simpleInputGestureData(
+                keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
+            ),
+        )
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index 57c8b44..f7c7701 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -16,12 +16,24 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.InputGestureData
+import android.hardware.input.fakeInputManager
+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.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
 import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allCustomizableInputGesturesWithSimpleShortcutCombinations
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.customInputGestureTypeHome
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.groupWithGoHomeShortcutInfo
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.systemCategoryWithCustomHomeShortcut
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.systemCategoryWithMergedGoHomeShortcut
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
@@ -34,6 +46,8 @@
 import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -42,13 +56,18 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() {
 
+    private val mockUserContext: Context = mock()
     private val systemShortcutsSource = FakeKeyboardShortcutGroupsSource()
     private val multitaskingShortcutsSource = FakeKeyboardShortcutGroupsSource()
+
     @OptIn(ExperimentalCoroutinesApi::class)
     private val kosmos =
         testKosmos().also {
@@ -57,17 +76,23 @@
             it.shortcutHelperMultiTaskingShortcutsSource = multitaskingShortcutsSource
             it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
             it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
         }
 
+    private val fakeInputManager = kosmos.fakeInputManager
     private val testScope = kosmos.testScope
-    private val interactor = kosmos.shortcutHelperCategoriesInteractor
+    private lateinit var interactor: ShortcutHelperCategoriesInteractor
     private val helper = kosmos.shortcutHelperTestHelper
+    private val inter by lazy { kosmos.shortcutHelperCategoriesInteractor }
 
     @Before
     fun setShortcuts() {
+        interactor = kosmos.shortcutHelperCategoriesInteractor
         helper.setImeShortcuts(TestShortcuts.imeGroups)
         systemShortcutsSource.setGroups(TestShortcuts.systemGroups)
         multitaskingShortcutsSource.setGroups(TestShortcuts.multitaskingGroups)
+        whenever(mockUserContext.getSystemService(INPUT_SERVICE))
+            .thenReturn(fakeInputManager.inputManager)
     }
 
     @Test
@@ -120,7 +145,7 @@
                     ShortcutCategory(
                         type = InputMethodEditor,
                         subCategories =
-                            TestShortcuts.imeSubCategoriesWithGroupedDuplicatedShortcutLabels
+                            TestShortcuts.imeSubCategoriesWithGroupedDuplicatedShortcutLabels,
                     ),
                 )
                 .inOrder()
@@ -140,7 +165,7 @@
                     ShortcutCategory(
                         type = System,
                         subCategories =
-                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels,
                     ),
                     TestShortcuts.multitaskingCategory,
                     TestShortcuts.imeCategory,
@@ -163,7 +188,7 @@
                     ShortcutCategory(
                         type = MultiTasking,
                         subCategories =
-                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels,
                     ),
                     TestShortcuts.imeCategory,
                 )
@@ -185,7 +210,7 @@
                     ShortcutCategory(
                         type = InputMethodEditor,
                         subCategories =
-                            TestShortcuts.imeSubCategoriesWithUnsupportedModifiersRemoved
+                            TestShortcuts.imeSubCategoriesWithUnsupportedModifiersRemoved,
                     ),
                 )
                 .inOrder()
@@ -203,7 +228,7 @@
                 .containsExactly(
                     ShortcutCategory(
                         type = System,
-                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved,
                     ),
                     TestShortcuts.multitaskingCategory,
                     TestShortcuts.imeCategory,
@@ -224,7 +249,7 @@
                     TestShortcuts.systemCategory,
                     ShortcutCategory(
                         type = MultiTasking,
-                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved,
                     ),
                     TestShortcuts.imeCategory,
                 )
@@ -240,10 +265,7 @@
             helper.showFromActivity()
 
             assertThat(categories)
-                .containsExactly(
-                    TestShortcuts.multitaskingCategory,
-                    TestShortcuts.imeCategory,
-                )
+                .containsExactly(TestShortcuts.multitaskingCategory, TestShortcuts.imeCategory)
                 .inOrder()
         }
 
@@ -256,10 +278,63 @@
             helper.showFromActivity()
 
             assertThat(categories)
-                .containsExactly(
-                    TestShortcuts.systemCategory,
-                    TestShortcuts.imeCategory,
-                )
+                .containsExactly(TestShortcuts.systemCategory, TestShortcuts.imeCategory)
                 .inOrder()
         }
+
+    @Test
+    @DisableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+    fun categories_excludesCustomShortcutsWhenFlagIsOff() {
+        testScope.runTest {
+            setCustomInputGestures(allCustomizableInputGesturesWithSimpleShortcutCombinations)
+            helper.showFromActivity()
+            val categories by collectLastValue(interactor.shortcutCategories)
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+    fun categories_includesCustomShortcutsWhenFlagIsOn() {
+        testScope.runTest {
+            setCustomInputGestures(listOf(customInputGestureTypeHome))
+            helper.showFromActivity()
+            val categories by collectLastValue(interactor.shortcutCategories)
+            assertThat(categories)
+                .containsExactly(
+                    systemCategoryWithCustomHomeShortcut,
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_KEYBOARD_SHORTCUT_HELPER_SHORTCUT_CUSTOMIZER)
+    fun categories_correctlyMergesDefaultAndCustomShortcutsOfSameType() {
+        testScope.runTest {
+            setCustomInputGestures(listOf(customInputGestureTypeHome))
+            systemShortcutsSource.setGroups(groupWithGoHomeShortcutInfo)
+            helper.showFromActivity()
+
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            assertThat(categories)
+                .containsExactly(
+                    systemCategoryWithMergedGoHomeShortcut,
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+        }
+    }
+
+    private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) {
+        whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
+            .thenReturn(customInputGestures)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
index 1580ea5..000024f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/ShortcutHelperDialogStarterTest.kt
@@ -16,6 +16,9 @@
 
 package com.android.systemui.keyboard.shortcut.ui
 
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.hardware.input.fakeInputManager
 import androidx.test.annotation.UiThreadTest
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -36,6 +39,8 @@
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.activityStarter
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.userTracker
 import com.android.systemui.statusbar.phone.systemUIDialogFactory
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,6 +49,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -52,7 +59,7 @@
 
     private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
     private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
-
+    private val mockUserContext: Context = mock()
     private val kosmos =
         Kosmos().also {
             it.testCase = this
@@ -62,8 +69,10 @@
             it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
             it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
             it.shortcutHelperCurrentAppShortcutsSource = FakeKeyboardShortcutGroupsSource()
+            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
         }
 
+    private val inputManager = kosmos.fakeInputManager.inputManager
     private val testScope = kosmos.testScope
     private val testHelper = kosmos.shortcutHelperTestHelper
     private val dialogFactory = kosmos.systemUIDialogFactory
@@ -85,6 +94,7 @@
     fun setUp() {
         fakeSystemSource.setGroups(TestShortcuts.systemGroups)
         fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
+        whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 92764ae..74a0bafda 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -17,6 +17,10 @@
 package com.android.systemui.keyguard.ui.binder
 
 import android.app.IActivityTaskManager
+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 androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -25,8 +29,10 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
+import com.android.window.flags.Flags
 import com.android.wm.shell.keyguard.KeyguardTransitions
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.eq
@@ -41,6 +47,9 @@
 @RunWith(AndroidJUnit4::class)
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
+
+    @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
     private lateinit var underTest: WindowManagerLockscreenVisibilityManager
     private lateinit var executor: FakeExecutor
 
@@ -68,32 +77,62 @@
     }
 
     @Test
-    fun testLockscreenVisible_andAodVisible() {
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testLockscreenVisible_andAodVisible_without_keyguard_shell_transitions() {
         underTest.setLockscreenShown(true)
-        underTest.setAodVisible(true)
-
         verify(activityTaskManagerService).setLockScreenShown(true, false)
+        underTest.setAodVisible(true)
         verify(activityTaskManagerService).setLockScreenShown(true, true)
+
         verifyNoMoreInteractions(activityTaskManagerService)
     }
 
     @Test
-    fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible() {
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testLockscreenVisible_andAodVisible_with_keyguard_shell_transitions() {
         underTest.setLockscreenShown(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, false)
         underTest.setAodVisible(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, true)
 
+        verifyNoMoreInteractions(keyguardTransitions)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible_without_keyguard_shell_transitions() {
+        underTest.setLockscreenShown(true)
         verify(activityTaskManagerService).setLockScreenShown(true, false)
+        underTest.setAodVisible(true)
         verify(activityTaskManagerService).setLockScreenShown(true, true)
+
         verifyNoMoreInteractions(activityTaskManagerService)
 
         underTest.setSurfaceBehindVisibility(true)
-
         verify(activityTaskManagerService).keyguardGoingAway(anyInt())
+
         verifyNoMoreInteractions(activityTaskManagerService)
     }
 
     @Test
-    fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway() {
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testGoingAway_whenLockscreenVisible_thenSurfaceMadeVisible_with_keyguard_shell_transitions() {
+        underTest.setLockscreenShown(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, false)
+        underTest.setAodVisible(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, true)
+
+        verifyNoMoreInteractions(keyguardTransitions)
+
+        underTest.setSurfaceBehindVisibility(true)
+        verify(keyguardTransitions).startKeyguardTransition(false, false)
+
+        verifyNoMoreInteractions(keyguardTransitions)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway_without_keyguard_shell_transitions() {
         underTest.setLockscreenShown(false)
         underTest.setAodVisible(false)
 
@@ -106,7 +145,22 @@
     }
 
     @Test
-    fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater() {
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testSurfaceVisible_whenLockscreenNotShowing_doesNotTriggerGoingAway_with_keyguard_shell_transitions() {
+        underTest.setLockscreenShown(false)
+        underTest.setAodVisible(false)
+
+        verify(keyguardTransitions).startKeyguardTransition(false, false)
+        verifyNoMoreInteractions(keyguardTransitions)
+
+        underTest.setSurfaceBehindVisibility(true)
+
+        verifyNoMoreInteractions(keyguardTransitions)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater_without_keyguard_shell_transitions() {
         underTest.setAodVisible(false)
         verifyNoMoreInteractions(activityTaskManagerService)
 
@@ -116,7 +170,19 @@
     }
 
     @Test
-    fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall() {
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun testAodVisible_noLockscreenShownCallYet_doesNotShowLockscreenUntilLater_with_keyguard_shell_transitions() {
+        underTest.setAodVisible(false)
+        verifyNoMoreInteractions(keyguardTransitions)
+
+        underTest.setLockscreenShown(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, false)
+        verifyNoMoreInteractions(activityTaskManagerService)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_without_keyguard_shell_transitions() {
         underTest.setLockscreenShown(true)
         underTest.setSurfaceBehindVisibility(true)
         verify(activityTaskManagerService).keyguardGoingAway(0)
@@ -126,8 +192,27 @@
     }
 
     @Test
-    fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility() {
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_with_keyguard_shell_transitions() {
+        underTest.setLockscreenShown(true)
+        underTest.setSurfaceBehindVisibility(true)
+        verify(keyguardTransitions).startKeyguardTransition(false, false)
+
+        underTest.setSurfaceBehindVisibility(true)
+        verifyNoMoreInteractions(keyguardTransitions)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility_without_keyguard_shell_transitions() {
         underTest.setSurfaceBehindVisibility(false)
         verify(activityTaskManagerService).setLockScreenShown(eq(true), any())
     }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
+    fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility_with_keyguard_shell_transitions() {
+        underTest.setSurfaceBehindVisibility(false)
+        verify(keyguardTransitions).startKeyguardTransition(eq(true), any())
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
index d94c97a..c0db95f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.res.R
 import com.android.systemui.shared.R as sharedR
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
 import com.android.systemui.util.mockito.any
@@ -68,6 +69,7 @@
     private val clockShouldBeCentered = MutableStateFlow(false)
     private val hasCustomWeatherDataDisplay = MutableStateFlow(false)
     private val isWeatherVisibleFlow = MutableStateFlow(false)
+    private val isShadeLayoutWide = MutableStateFlow(false)
 
     @Before
     fun setup() {
@@ -80,7 +82,7 @@
                 keyguardSmartspaceInteractor,
                 lockscreenSmartspaceController,
                 keyguardUnlockAnimationController,
-                blueprintInteractor
+                blueprintInteractor,
             )
         constraintLayout = ConstraintLayout(mContext)
         whenever(lockscreenSmartspaceController.buildAndConnectView(any()))
@@ -93,6 +95,7 @@
         whenever(keyguardClockViewModel.clockShouldBeCentered).thenReturn(clockShouldBeCentered)
         whenever(keyguardSmartspaceViewModel.isSmartspaceEnabled).thenReturn(true)
         whenever(keyguardSmartspaceViewModel.isWeatherVisible).thenReturn(isWeatherVisibleFlow)
+        whenever(keyguardSmartspaceViewModel.isShadeLayoutWide).thenReturn(isShadeLayoutWide)
         constraintSet = ConstraintSet()
     }
 
@@ -125,6 +128,26 @@
     }
 
     @Test
+    fun testConstraintsWhenShadeLayoutIsNotWide() {
+        underTest.addViews(constraintLayout)
+        underTest.applyConstraints(constraintSet)
+
+        val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id)
+        assertThat(smartspaceConstraints.layout.endToEnd).isEqualTo(ConstraintSet.PARENT_ID)
+    }
+
+    @Test
+    fun testConstraintsWhenShadeLayoutIsWide() {
+        isShadeLayoutWide.value = true
+
+        underTest.addViews(constraintLayout)
+        underTest.applyConstraints(constraintSet)
+
+        val smartspaceConstraints = constraintSet.getConstraint(smartspaceView.id)
+        assertThat(smartspaceConstraints.layout.endToEnd).isEqualTo(R.id.split_shade_guideline)
+    }
+
+    @Test
     fun testConstraintsWhenNotHasCustomWeatherDataDisplay() {
         whenever(keyguardSmartspaceViewModel.isDateWeatherDecoupled).thenReturn(true)
         underTest.addViews(constraintLayout)
@@ -160,6 +183,7 @@
         assertThat(constraintSet.getVisibility(weatherView.id)).isEqualTo(GONE)
         assertThat(constraintSet.getVisibility(dateView.id)).isEqualTo(VISIBLE)
     }
+
     @Test
     fun testCustomDateWeatherVisibility() {
         hasCustomWeatherDataDisplay.value = true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
index 0c3fcb3..adce9d6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.shared.model.ClockSize
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
@@ -96,4 +97,26 @@
 
             assertThat(isWeatherVisible).isEqualTo(false)
         }
+
+    @Test
+    fun isShadeLayoutWide_withConfigTrue_true() =
+        with(kosmos) {
+            testScope.runTest {
+                val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+                shadeRepository.setShadeLayoutWide(true)
+
+                assertThat(isShadeLayoutWide).isTrue()
+            }
+        }
+
+    @Test
+    fun isShadeLayoutWide_withConfigFalse_false() =
+        with(kosmos) {
+            testScope.runTest {
+                val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
+                shadeRepository.setShadeLayoutWide(false)
+
+                assertThat(isShadeLayoutWide).isFalse()
+            }
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
index 450aadd..ebc00c3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/FakeNoteTaskBubbleController.kt
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.graphics.drawable.Icon
 import android.os.UserHandle
+import com.android.wm.shell.bubbles.Bubble
 import com.android.wm.shell.bubbles.Bubbles
 import java.util.Optional
 import kotlinx.coroutines.CoroutineDispatcher
@@ -33,14 +34,29 @@
 class FakeNoteTaskBubbleController(
     unUsed1: Context,
     unsUsed2: CoroutineDispatcher,
-    private val optionalBubbles: Optional<Bubbles>
+    private val optionalBubbles: Optional<Bubbles>,
 ) : NoteTaskBubblesController(unUsed1, unsUsed2) {
     override suspend fun areBubblesAvailable() = optionalBubbles.isPresent
 
-    override suspend fun showOrHideAppBubble(intent: Intent, userHandle: UserHandle, icon: Icon) {
+    override suspend fun showOrHideAppBubble(
+        intent: Intent,
+        userHandle: UserHandle,
+        icon: Icon,
+        bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
+    ) {
         optionalBubbles.ifPresentOrElse(
-            { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
-            { throw IllegalAccessException() }
+            { bubbles ->
+                if (
+                    bubbleExpandBehavior == NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED &&
+                        bubbles.isBubbleExpanded(
+                            Bubble.getAppBubbleKeyForApp(intent.`package`, userHandle)
+                        )
+                ) {
+                    return@ifPresentOrElse
+                }
+                bubbles.showOrHideAppBubble(intent, userHandle, icon)
+            },
+            { throw IllegalAccessException() },
         )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
index 9ef6b9c..e55d6ad 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskBubblesServiceTest.kt
@@ -21,9 +21,9 @@
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.notetask.NoteTaskBubblesController.NoteTaskBubblesService
+import com.android.systemui.res.R
 import com.android.wm.shell.bubbles.Bubbles
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
@@ -33,6 +33,9 @@
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.whenever
 
 /** atest SystemUITests:NoteTaskBubblesServiceTest */
 @SmallTest
@@ -61,12 +64,40 @@
     }
 
     @Test
-    fun showOrHideAppBubble() {
+    fun showOrHideAppBubble_defaultExpandBehavior_shouldCallBubblesApi() {
         val intent = Intent()
         val user = UserHandle.SYSTEM
         val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+        val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.DEFAULT
+        whenever(bubbles.isBubbleExpanded(any())).thenReturn(false)
 
-        createServiceBinder().showOrHideAppBubble(intent, user, icon)
+        createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
+
+        verify(bubbles).showOrHideAppBubble(intent, user, icon)
+    }
+
+    @Test
+    fun showOrHideAppBubble_keepIfExpanded_bubbleShown_shouldNotCallBubblesApi() {
+        val intent = Intent().apply { setPackage("test") }
+        val user = UserHandle.SYSTEM
+        val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+        val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED
+        whenever(bubbles.isBubbleExpanded(any())).thenReturn(true)
+
+        createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
+
+        verify(bubbles, never()).showOrHideAppBubble(intent, user, icon)
+    }
+
+    @Test
+    fun showOrHideAppBubble_keepIfExpanded_bubbleNotShown_shouldCallBubblesApi() {
+        val intent = Intent().apply { setPackage("test") }
+        val user = UserHandle.SYSTEM
+        val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+        val bubbleExpandBehavior = NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED
+        whenever(bubbles.isBubbleExpanded(any())).thenReturn(false)
+
+        createServiceBinder().showOrHideAppBubble(intent, user, icon, bubbleExpandBehavior)
 
         verify(bubbles).showOrHideAppBubble(intent, user, icon)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
index 8f4078b..d3578fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.notetask.NoteTaskEntryPoint.QS_NOTES_TILE
 import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -44,10 +45,19 @@
     }
 
     @Test
-    fun launchMode_keyguardUnlocked_launchModeAppBubble() {
+    fun launchMode_keyguardUnlocked_launchModeAppBubble_withDefaultExpandBehavior() {
         val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false)
 
-        assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.AppBubble)
+        assertThat(underTest.launchMode)
+            .isEqualTo(NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.DEFAULT))
+    }
+
+    @Test
+    fun launchMode_keyguardUnlocked_qsTileEntryPoint_launchModeAppBubble_withKeepIfExpandedExpandBehavior() {
+        val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false, entryPoint = QS_NOTES_TILE)
+
+        assertThat(underTest.launchMode)
+            .isEqualTo(NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED))
     }
 
     private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 83f95ea..e9633f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -21,9 +21,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static kotlinx.coroutines.flow.FlowKt.asStateFlow;
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -39,6 +36,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.flow.FlowKt.asStateFlow;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.platform.test.annotations.DisableFlags;
@@ -70,9 +70,6 @@
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.util.animation.DisappearParameters;
 
-import kotlinx.coroutines.flow.MutableStateFlow;
-import kotlinx.coroutines.flow.StateFlow;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -88,6 +85,8 @@
 
 import javax.inject.Provider;
 
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlow;
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
 
@@ -232,6 +231,7 @@
 
     @After
     public void tearDown() {
+        mController.destroy();
         disallowTestableLooperAsMainThread();
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 02c5b5a..96f6a62 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -1,10 +1,10 @@
 package com.android.systemui.qs
 
 import android.content.res.Configuration
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
 import android.testing.TestableResources
 import android.view.ContextThemeWrapper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
@@ -37,8 +37,8 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -81,37 +81,39 @@
         setShouldUseSplitShade(false)
         whenever(qsPanel.resources).thenReturn(testableResources.resources)
         whenever(qsPanel.context)
-                .thenReturn( ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings))
+            .thenReturn(ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings))
         whenever(qsPanel.getOrCreateTileLayout()).thenReturn(pagedTileLayout)
         whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false)
         whenever(qsPanel.setListening(anyBoolean())).then {
             whenever(qsPanel.isListening).thenReturn(it.getArgument(0))
         }
 
-        controller = QSPanelController(
-            qsPanel,
-            tunerService,
-            qsHost,
-            qsCustomizerController,
-            /* usingMediaPlayer= */ usingMediaPlayer,
-            mediaHost,
-            qsTileRevealControllerFactory,
-            dumpManager,
-            metricsLogger,
-            uiEventLogger,
-            qsLogger,
-            brightnessControllerFactory,
-            brightnessSliderFactory,
-            falsingManager,
-            statusBarKeyguardViewManager,
-            ResourcesSplitShadeStateController(),
-            longPressEffectProvider,
-            mediaCarouselInteractor,
-        )
+        controller =
+            QSPanelController(
+                qsPanel,
+                tunerService,
+                qsHost,
+                qsCustomizerController,
+                /* usingMediaPlayer= */ usingMediaPlayer,
+                mediaHost,
+                qsTileRevealControllerFactory,
+                dumpManager,
+                metricsLogger,
+                uiEventLogger,
+                qsLogger,
+                brightnessControllerFactory,
+                brightnessSliderFactory,
+                falsingManager,
+                statusBarKeyguardViewManager,
+                ResourcesSplitShadeStateController(),
+                longPressEffectProvider,
+                mediaCarouselInteractor,
+            )
     }
 
     @After
     fun tearDown() {
+        controller.destroy()
         reset(mediaHost)
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 369bb22..7880ace 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
 import com.android.systemui.util.leak.RotationUtils
+import javax.inject.Provider
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -45,9 +46,8 @@
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import javax.inject.Provider
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -108,6 +108,7 @@
     @After
     fun tearDown() {
         controller.onViewDetached()
+        controller.destroy()
     }
 
     @Test
@@ -184,7 +185,7 @@
             dumpManager,
             ResourcesSplitShadeStateController(),
             longPressEffectProvider,
-            mediaCarouselInteractor
+            mediaCarouselInteractor,
         ) {
 
         private var rotation = RotationUtils.ROTATION_NONE
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/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/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
index f192b59..8ef1e56 100644
--- 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
@@ -28,7 +28,7 @@
 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.FakeShadePositionRepository
+import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository
 import com.android.systemui.statusbar.phone.ConfigurationForwarder
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
@@ -50,7 +50,7 @@
 class ShadeDisplaysInteractorTest : SysuiTestCase() {
 
     private val shadeRootview = mock<WindowRootView>()
-    private val positionRepository = FakeShadePositionRepository()
+    private val positionRepository = FakeShadeDisplayRepository()
     private val defaultContext = mock<Context>()
     private val secondaryContext = mock<Context>()
     private val contextStore = FakeDisplayWindowPropertiesRepository()
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/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index fb7252b..60a1855 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static android.app.Notification.CATEGORY_CALL;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.Assert.assertEquals;
@@ -199,19 +197,6 @@
     }
 
     @Test
-    public void testContentDescForNotification_noNotifContent() {
-        Notification n = new Notification.Builder(mContext, "test")
-                .setSmallIcon(0)
-                .setContentTitle("hello")
-                .setCategory(CATEGORY_CALL)
-                .build();
-        assertThat(NotificationContentDescription.contentDescForNotification(mContext, n)
-                .toString()).startsWith("com.android.systemui.tests notification");
-        assertThat(NotificationContentDescription.contentDescForNotification(mContext, n)
-                .toString()).doesNotContain("hello");
-    }
-
-    @Test
     @EnableFlags({Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS})
     public void setIcon_withPreloaded_usesPreloaded() {
         Icon mockIcon = mock(Icon.class);
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/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/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/multivalentTests/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
index d823bf5..4eef308 100644
--- a/packages/SystemUI/multivalentTests/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/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
index 0e32c95..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
@@ -24,6 +24,7 @@
 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
@@ -65,6 +66,7 @@
     private lateinit var underTest: ModesDialogViewModel
 
     private lateinit var timeScheduleMode: ZenMode
+    private lateinit var timeScheduleInfo: ScheduleInfo
 
     @Before
     fun setUp() {
@@ -78,18 +80,18 @@
                 kosmos.mockModesDialogEventLogger,
             )
 
-        val scheduleInfo = ZenModeConfig.ScheduleInfo()
-        scheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY)
-        scheduleInfo.startHour = 11
-        scheduleInfo.endHour = 15
+        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(scheduleInfo))
+                .setConditionId(ZenModeConfig.toScheduleConditionId(timeScheduleInfo))
                 .setTriggerDescription(
-                    SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, scheduleInfo)
+                    SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, timeScheduleInfo)
                 )
                 .build()
     }
@@ -358,7 +360,7 @@
             assertThat(tiles!![3].subtext).isEqualTo("Off")
             assertThat(tiles!![4].subtext).isEqualTo("On")
             assertThat(tiles!![5].subtext).isEqualTo("Not set")
-            assertThat(tiles!![6].subtext).isEqualTo("Mon - Wed, 11:00 AM - 3:00 PM")
+            assertThat(tiles!![6].subtext).isEqualTo(timeScheduleMode.triggerDescription)
         }
 
     @Test
@@ -437,7 +439,8 @@
             with(tiles?.elementAt(6)!!) {
                 assertThat(this.stateDescription).isEqualTo("Off")
                 assertThat(this.subtextDescription)
-                    .isEqualTo("Monday to Wednesday, 11:00 AM - 3:00 PM")
+                    .isEqualTo(SystemZenRules.getDaysOfWeekFull(context, timeScheduleInfo)
+                    + ", " + SystemZenRules.getTimeSummary(context, timeScheduleInfo))
             }
 
             // All tiles have the same long click info
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/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
index 2e6d0fc..e25bf13 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
@@ -27,7 +27,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
@@ -57,7 +57,7 @@
     @Before
     fun setUp() {
         testScope = TestScope(testDispatcher)
-        mSettings = FakeSettingsProxy(testDispatcher)
+        mSettings = FakeSettingsProxy(testScope)
         mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
     }
 
@@ -92,7 +92,7 @@
             mSettings.registerContentObserverSync(
                 TEST_SETTING,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -104,7 +104,7 @@
             mSettings.registerContentObserver(
                 TEST_SETTING,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -116,7 +116,7 @@
             mSettings.registerContentObserverAsync(
                 TEST_SETTING,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             testScope.advanceUntilIdle()
             verify(mSettings.getContentResolver())
@@ -154,7 +154,7 @@
             mSettings.registerContentObserverSync(
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -166,7 +166,7 @@
             mSettings.registerContentObserver(
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver))
@@ -178,7 +178,7 @@
             mSettings.registerContentObserverAsync(
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             testScope.advanceUntilIdle()
             verify(mSettings.getContentResolver())
@@ -202,7 +202,7 @@
                     TEST_SETTING_URI,
                     false,
                     mContentObserver,
-                    it
+                    it,
                 )
             }
         }
@@ -382,15 +382,15 @@
         assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F)
     }
 
-    private class FakeSettingsProxy(val testDispatcher: CoroutineDispatcher) : SettingsProxy {
+    private class FakeSettingsProxy(val testScope: CoroutineScope) : SettingsProxy {
 
         private val mContentResolver = mock(ContentResolver::class.java)
         private val settingToValueMap: MutableMap<String, String?> = mutableMapOf()
 
         override fun getContentResolver() = mContentResolver
 
-        override val backgroundDispatcher: CoroutineDispatcher
-            get() = testDispatcher
+        override val settingsScope: CoroutineScope
+            get() = testScope
 
         override fun getUriFor(name: String) =
             Uri.parse(StringBuilder().append("content://settings/").append(name).toString())
@@ -408,7 +408,7 @@
             name: String,
             value: String?,
             tag: String?,
-            makeDefault: Boolean
+            makeDefault: Boolean,
         ): Boolean {
             settingToValueMap[name] = value
             return true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
index 00b8cd0..5787f7d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
@@ -28,7 +28,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -36,7 +36,6 @@
 import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertThrows
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
@@ -51,14 +50,9 @@
 
     private var userId = MAIN_USER_ID
     private val testDispatcher = StandardTestDispatcher()
-    private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testDispatcher)
+    private val testScope = TestScope(testDispatcher)
+    private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testScope)
     private var mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {}
-    private lateinit var testScope: TestScope
-
-    @Before
-    fun setUp() {
-        testScope = TestScope(testDispatcher)
-    }
 
     @Test
     fun registerContentObserverForUser_inputString_success() =
@@ -69,7 +63,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -82,7 +76,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -96,7 +90,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -107,14 +101,14 @@
                 TEST_SETTING,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -125,16 +119,14 @@
                 TEST_SETTING,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(
                     eq(TEST_SETTING_URI),
-                    eq(
-                        true,
-                    ),
+                    eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -145,7 +137,7 @@
                 TEST_SETTING,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             testScope.advanceUntilIdle()
             verify(mSettings.getContentResolver())
@@ -153,7 +145,7 @@
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -166,7 +158,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -179,7 +171,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -189,7 +181,7 @@
             mSettings.registerContentObserverForUserAsync(
                 TEST_SETTING_URI,
                 mContentObserver,
-                userId
+                userId,
             )
             testScope.advanceUntilIdle()
 
@@ -198,7 +190,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -213,7 +205,7 @@
                 TEST_SETTING_URI,
                 mContentObserver,
                 userId,
-                runnable
+                runnable,
             )
             testScope.advanceUntilIdle()
             assertThat(callbackCalled).isTrue()
@@ -226,14 +218,14 @@
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -244,14 +236,14 @@
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -262,7 +254,7 @@
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
                 mContentObserver,
-                userId
+                userId,
             )
             testScope.advanceUntilIdle()
             verify(mSettings.getContentResolver())
@@ -270,7 +262,7 @@
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(MAIN_USER_ID)
+                    eq(MAIN_USER_ID),
                 )
         }
 
@@ -283,7 +275,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(0)
+                    eq(0),
                 )
         }
 
@@ -296,7 +288,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(0)
+                    eq(0),
                 )
         }
 
@@ -309,7 +301,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(0)
+                    eq(0),
                 )
         }
     }
@@ -320,14 +312,14 @@
             mSettings.registerContentObserverSync(
                 TEST_SETTING_URI,
                 notifyForDescendants = true,
-                mContentObserver
+                mContentObserver,
             )
             verify(mSettings.getContentResolver())
                 .registerContentObserver(
                     eq(TEST_SETTING_URI),
                     eq(true),
                     eq(mContentObserver),
-                    eq(0)
+                    eq(0),
                 )
         }
 
@@ -340,7 +332,7 @@
                     eq(TEST_SETTING_URI),
                     eq(false),
                     eq(mContentObserver),
-                    eq(0)
+                    eq(0),
                 )
         }
 
@@ -354,7 +346,7 @@
                         eq(TEST_SETTING_URI),
                         eq(false),
                         eq(mContentObserver),
-                        eq(0)
+                        eq(0),
                     )
             }
         }
@@ -557,7 +549,7 @@
      */
     private class FakeUserSettingsProxy(
         override val currentUserProvider: SettingsProxy.CurrentUserIdProvider,
-        val testDispatcher: CoroutineDispatcher
+        val testScope: CoroutineScope,
     ) : UserSettingsProxy {
 
         private val mContentResolver = mock(ContentResolver::class.java)
@@ -569,8 +561,8 @@
         override fun getUriFor(name: String) =
             Uri.parse(StringBuilder().append(URI_PREFIX).append(name).toString())
 
-        override val backgroundDispatcher: CoroutineDispatcher
-            get() = testDispatcher
+        override val settingsScope: CoroutineScope
+            get() = testScope
 
         override fun getStringForUser(name: String, userHandle: Int) =
             userIdToSettingsValueMap[userHandle]?.get(name) ?: ""
@@ -578,7 +570,7 @@
         override fun putString(
             name: String,
             value: String?,
-            overrideableByRestore: Boolean
+            overrideableByRestore: Boolean,
         ): Boolean {
             userIdToSettingsValueMap[DEFAULT_USER_ID]?.put(name, value)
             return true
@@ -588,7 +580,7 @@
             name: String,
             value: String?,
             tag: String?,
-            makeDefault: Boolean
+            makeDefault: Boolean,
         ): Boolean {
             putStringForUser(name, value, DEFAULT_USER_ID)
             return true
@@ -605,7 +597,7 @@
             tag: String?,
             makeDefault: Boolean,
             userHandle: Int,
-            overrideableByRestore: Boolean
+            overrideableByRestore: Boolean,
         ): Boolean {
             userIdToSettingsValueMap[userHandle]?.set(name, value)
             return true
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 1914867..75f3386 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -39,14 +40,13 @@
 import android.media.session.MediaSession;
 import android.os.Handler;
 import android.os.Process;
-import android.platform.test.annotations.EnableFlags;
 import android.testing.TestableLooper;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.settingslib.flags.Flags;
+import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestCaseExtKt;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -64,6 +64,10 @@
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.domain.interactor.FakeAudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
+
+import kotlinx.coroutines.test.TestScope;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -94,6 +98,9 @@
     private RingerModeLiveData mRingerModeInternalLiveData;
     private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
             new FakeExecutor(new FakeSystemClock()));
+    private final TestScope mTestScope = TestScopeProvider.getTestScope();
+    private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope);
+    private FakeAudioSharingInteractor mFakeAudioSharingInteractor;
     @Mock
     private AudioManager mAudioManager;
     @Mock
@@ -117,9 +124,7 @@
     @Mock
     private DumpManager mDumpManager;
     @Mock
-    private AudioSharingInteractor mAudioSharingInteractor;
-    @Mock
-    private JavaAdapter mJavaAdapter;
+    private VolumeLogger mVolumeLogger;
 
 
     @Before
@@ -136,6 +141,8 @@
 
         mCallback = mock(VolumeDialogControllerImpl.C.class);
         mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
+        mFakeAudioSharingInteractor = spy(new FakeAudioSharingInteractor());
+        mFakeAudioSharingInteractor.setAudioSharingVolumeBarAvailable(true);
         mVolumeController =
                 new TestableVolumeDialogControllerImpl(
                         mContext,
@@ -155,8 +162,9 @@
                         mUserTracker,
                         mDumpManager,
                         mCallback,
-                        mAudioSharingInteractor,
-                        mJavaAdapter);
+                        mFakeAudioSharingInteractor,
+                        mJavaAdapter,
+                        mVolumeLogger);
         mVolumeController.setEnableDialogs(true, true);
     }
 
@@ -305,13 +313,13 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_VOLUME_DIALOG_AUDIO_SHARING_FIX)
     public void testSetStreamVolume_setSecondaryDeviceVolume() {
         mVolumeController.setStreamVolume(
                 VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST, /* level= */ 100);
         Objects.requireNonNull(TestableLooper.get(this)).processAllMessages();
+        mTestScope.getTestScheduler().advanceUntilIdle();
 
-        verify(mAudioSharingInteractor).setStreamVolume(100);
+        verify(mFakeAudioSharingInteractor).setStreamVolume(100);
     }
 
     static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
@@ -336,7 +344,8 @@
                 DumpManager dumpManager,
                 C callback,
                 AudioSharingInteractor audioSharingInteractor,
-                JavaAdapter javaAdapter) {
+                JavaAdapter javaAdapter,
+                VolumeLogger volumeLogger) {
             super(
                     context,
                     broadcastDispatcher,
@@ -355,7 +364,8 @@
                     userTracker,
                     dumpManager,
                     audioSharingInteractor,
-                    javaAdapter);
+                    javaAdapter,
+                    volumeLogger);
             mCallbacks = callback;
 
             ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
index 76b7b8f..a9c352d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeDialogControllerImplTestKt.kt
@@ -49,9 +49,10 @@
 import com.android.systemui.util.RingerModeLiveData
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.concurrency.FakeThreadFactory
+import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.time.fakeSystemClock
 import com.android.systemui.volume.data.repository.audioRepository
-import com.android.systemui.volume.domain.interactor.audioSharingInteractor
+import com.android.systemui.volume.domain.interactor.FakeAudioSharingInteractor
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -76,6 +77,9 @@
     private val kosmos: Kosmos = testKosmos()
     private val audioManager: AudioManager = mock {}
     private val callbacks: VolumeDialogController.Callbacks = mock {}
+    private val javaAdapter: JavaAdapter = JavaAdapter(kosmos.testScope)
+    private val fakeAudioSharingInteractor: FakeAudioSharingInteractor =
+        FakeAudioSharingInteractor()
 
     private lateinit var threadFactory: FakeThreadFactory
     private lateinit var underTest: VolumeDialogControllerImpl
@@ -87,6 +91,8 @@
             threadFactory =
                 FakeThreadFactory(FakeExecutor(fakeSystemClock)).apply { setLooper(looper) }
             broadcastDispatcherContext = testableContext
+            fakeAudioSharingInteractor.setAudioSharingVolumeBarAvailable(true)
+
             underTest =
                 VolumeDialogControllerImpl(
                         applicationContext,
@@ -108,7 +114,8 @@
                         activityManager,
                         mock { on { userContext }.thenReturn(applicationContext) },
                         dumpManager,
-                        audioSharingInteractor,
+                        fakeAudioSharingInteractor,
+                        javaAdapter,
                         mock {},
                     )
                     .apply {
@@ -129,6 +136,7 @@
                     },
                 )
                 testableLooper.processAllMessages()
+                testScheduler.advanceUntilIdle()
 
                 verify(callbacks) { 1 * { onStateChanged(any()) } }
             }
@@ -163,6 +171,7 @@
                 emitVolumeChange(AudioManager.STREAM_SYSTEM, AudioManager.FLAG_SHOW_UI)
                 runCurrent()
                 TestableLooper.get(this@VolumeDialogControllerImplTestKt).processAllMessages()
+                testScheduler.advanceUntilIdle()
 
                 verify(callbacks) { 1 * { onShowRequested(any(), any(), any()) } }
             }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
index 7c5a487..3f995c6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractorTest.kt
@@ -155,6 +155,30 @@
             }
         }
 
+    @Test
+    fun activeStreamChanges_showBoth() {
+        with(kosmos) {
+            testScope.runTest {
+                runCurrent()
+                fakeVolumeDialogController.updateState {
+                    activeStream = AudioManager.STREAM_SYSTEM
+                    states.put(AudioManager.STREAM_MUSIC, buildStreamState())
+                    states.put(AudioManager.STREAM_SYSTEM, buildStreamState())
+                }
+                val slidersModel by collectLastValue(underTest.sliders)
+                runCurrent()
+
+                fakeVolumeDialogController.updateState { activeStream = AudioManager.STREAM_MUSIC }
+                runCurrent()
+
+                assertThat(slidersModel!!.slider)
+                    .isEqualTo(VolumeDialogSliderType.Stream(AudioManager.STREAM_MUSIC))
+                assertThat(slidersModel!!.floatingSliders)
+                    .containsExactly(VolumeDialogSliderType.Stream(AudioManager.STREAM_SYSTEM))
+            }
+        }
+    }
+
     private fun buildStreamState(
         build: VolumeDialogController.StreamState.() -> Unit = {}
     ): VolumeDialogController.StreamState {
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
index d68501f..6b90952 100644
--- a/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -25,7 +25,7 @@
 
 import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
 
 import javax.inject.Inject;
 
@@ -33,13 +33,13 @@
 @SuppressLint("StaticSettingsProvider")
 class GlobalSettingsImpl implements GlobalSettings {
     private final ContentResolver mContentResolver;
-    private final CoroutineDispatcher mBgDispatcher;
+    private final CoroutineScope mSettingsScope;
 
     @Inject
     GlobalSettingsImpl(ContentResolver contentResolver,
-            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineScope settingsScope) {
         mContentResolver = contentResolver;
-        mBgDispatcher = bgDispatcher;
+        mSettingsScope = settingsScope;
     }
 
     @NonNull
@@ -56,8 +56,8 @@
 
     @NonNull
     @Override
-    public CoroutineDispatcher getBackgroundDispatcher() {
-        return mBgDispatcher;
+    public CoroutineScope getSettingsScope() {
+        return mSettingsScope;
     }
 
     @Override
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
index 211a6f4..ae89a5f 100644
--- a/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -23,23 +23,23 @@
 
 import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
 
 import javax.inject.Inject;
 
 class SecureSettingsImpl implements SecureSettings {
     private final ContentResolver mContentResolver;
     private final CurrentUserIdProvider mCurrentUserProvider;
-    private final CoroutineDispatcher mBgDispatcher;
+    private final CoroutineScope mSettingsScope;
 
     @Inject
     SecureSettingsImpl(
             ContentResolver contentResolver,
             CurrentUserIdProvider currentUserProvider,
-            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineScope settingsScope) {
         mContentResolver = contentResolver;
         mCurrentUserProvider = currentUserProvider;
-        mBgDispatcher = bgDispatcher;
+        mSettingsScope = settingsScope;
     }
 
     @NonNull
@@ -62,8 +62,8 @@
 
     @NonNull
     @Override
-    public CoroutineDispatcher getBackgroundDispatcher() {
-        return mBgDispatcher;
+    public CoroutineScope getSettingsScope() {
+        return mSettingsScope;
     }
 
     @Override
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
index 5d0b0d5..154d3cc 100644
--- a/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt
@@ -23,10 +23,12 @@
 import androidx.annotation.AnyThread
 import androidx.annotation.WorkerThread
 import com.android.app.tracing.TraceUtils.trace
-import com.android.systemui.coroutines.newTracingContext
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.app.tracing.coroutines.nameCoroutine
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 /**
@@ -47,11 +49,14 @@
     /** Returns the [ContentResolver] this instance was constructed with. */
     fun getContentResolver(): ContentResolver
 
-    /**
-     * Returns the background [CoroutineDispatcher] that the async APIs will use for a specific
-     * implementation.
-     */
-    val backgroundDispatcher: CoroutineDispatcher
+    /** Returns the [CoroutineScope] that the async APIs will use. */
+    val settingsScope: CoroutineScope
+
+    @OptIn(ExperimentalStdlibApi::class)
+    fun settingsDispatcherContext(name: String): CoroutineContext {
+        return (settingsScope.coroutineContext[CoroutineDispatcher] ?: EmptyCoroutineContext) +
+            nameCoroutine(name)
+    }
 
     /**
      * Construct the content URI for a particular name/value pair, useful for monitoring changes
@@ -82,7 +87,7 @@
      * wish to synchronize execution.
      */
     suspend fun registerContentObserver(name: String, settingsObserver: ContentObserver) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserver-A")) {
             registerContentObserverSync(getUriFor(name), settingsObserver)
         }
     }
@@ -94,7 +99,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-A")).launch {
+        settingsScope.launch("registerContentObserverAsync-A") {
             registerContentObserverSync(getUriFor(name), settingsObserver)
         }
 
@@ -111,7 +116,7 @@
         settingsObserver: ContentObserver,
         @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-B")).launch {
+        settingsScope.launch("registerContentObserverAsync-B") {
             registerContentObserverSync(getUriFor(name), settingsObserver)
             registered.run()
         }
@@ -134,7 +139,9 @@
      * wish to synchronize execution.
      */
     suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
-        withContext(backgroundDispatcher) { registerContentObserverSync(uri, settingsObserver) }
+        withContext(settingsDispatcherContext("registerContentObserver-B")) {
+            registerContentObserverSync(uri, settingsObserver)
+        }
     }
 
     /**
@@ -144,7 +151,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-C")).launch {
+        settingsScope.launch("registerContentObserverAsync-C") {
             registerContentObserverSync(uri, settingsObserver)
         }
 
@@ -161,7 +168,7 @@
         settingsObserver: ContentObserver,
         @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-D")).launch {
+        settingsScope.launch("registerContentObserverAsync-D") {
             registerContentObserverSync(uri, settingsObserver)
             registered.run()
         }
@@ -188,9 +195,9 @@
     suspend fun registerContentObserver(
         name: String,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserver-C")) {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
         }
     }
@@ -206,7 +213,7 @@
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-E")).launch {
+        settingsScope.launch("registerContentObserverAsync-E") {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
         }
 
@@ -224,7 +231,7 @@
         settingsObserver: ContentObserver,
         @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-F")).launch {
+        settingsScope.launch("registerContentObserverAsync-F") {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -239,7 +246,7 @@
     fun registerContentObserverSync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
         trace({ "SP#registerObserver#[$uri]" }) {
             getContentResolver()
@@ -257,9 +264,9 @@
     suspend fun registerContentObserver(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserver-D")) {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
         }
     }
@@ -275,7 +282,7 @@
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-G")).launch {
+        settingsScope.launch("registerContentObserverAsync-G") {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
         }
 
@@ -293,7 +300,7 @@
         settingsObserver: ContentObserver,
         @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-H")).launch {
+        settingsScope.launch("registerContentObserverAsync-H") {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -319,7 +326,9 @@
      * async block if they wish to synchronize execution.
      */
     suspend fun unregisterContentObserver(settingsObserver: ContentObserver) {
-        withContext(backgroundDispatcher) { unregisterContentObserverSync(settingsObserver) }
+        withContext(settingsDispatcherContext("unregisterContentObserver")) {
+            unregisterContentObserverSync(settingsObserver)
+        }
     }
 
     /**
@@ -330,7 +339,7 @@
      */
     @AnyThread
     fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-I")).launch {
+        settingsScope.launch("unregisterContentObserverAsync") {
             unregisterContentObserver(settingsObserver)
         }
 
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
index 1b3f74e..65d1c27 100644
--- a/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -23,22 +23,22 @@
 
 import com.android.systemui.util.settings.SettingsSingleThreadBackground;
 
-import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
 
 import javax.inject.Inject;
 
 class SystemSettingsImpl implements SystemSettings {
     private final ContentResolver mContentResolver;
     private final CurrentUserIdProvider mCurrentUserProvider;
-    private final CoroutineDispatcher mBgCoroutineDispatcher;
+    private final CoroutineScope mSettingsScope;
 
     @Inject
     SystemSettingsImpl(ContentResolver contentResolver,
             CurrentUserIdProvider currentUserProvider,
-            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineScope settingsScope) {
         mContentResolver = contentResolver;
         mCurrentUserProvider = currentUserProvider;
-        mBgCoroutineDispatcher = bgDispatcher;
+        mSettingsScope = settingsScope;
     }
 
     @NonNull
@@ -61,8 +61,8 @@
 
     @NonNull
     @Override
-    public CoroutineDispatcher getBackgroundDispatcher() {
-        return mBgCoroutineDispatcher;
+    public CoroutineScope getSettingsScope() {
+        return mSettingsScope;
     }
 
     @Override
diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
index 4b03df6..1a55170 100644
--- a/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -23,13 +23,11 @@
 import android.os.UserHandle
 import android.provider.Settings.SettingNotFoundException
 import com.android.app.tracing.TraceUtils.trace
-import com.android.systemui.coroutines.newTracingContext
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault
-import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 /**
@@ -73,13 +71,13 @@
     }
 
     override suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserver-A")) {
             registerContentObserverForUserSync(uri, settingsObserver, userId)
         }
     }
 
     override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-A")).launch {
+        settingsScope.launch("registerContentObserverAsync-A") {
             registerContentObserverForUserSync(uri, settingsObserver, userId)
         }
 
@@ -96,9 +94,9 @@
     override suspend fun registerContentObserver(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserver-B")) {
             registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
         }
     }
@@ -113,7 +111,7 @@
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-B")).launch {
+        settingsScope.launch("registerContentObserverAsync-B") {
             registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
         }
 
@@ -126,7 +124,7 @@
     fun registerContentObserverForUserSync(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
         registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
     }
@@ -141,9 +139,9 @@
     suspend fun registerContentObserverForUser(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserverForUser-A")) {
             registerContentObserverForUserSync(name, settingsObserver, userHandle)
         }
     }
@@ -158,7 +156,7 @@
         settingsObserver: ContentObserver,
         userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-C")).launch {
+        settingsScope.launch("registerContentObserverForUserAsync-A") {
             registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
         }
 
@@ -167,7 +165,7 @@
     fun registerContentObserverForUserSync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
         registerContentObserverForUserSync(uri, false, settingsObserver, userHandle)
     }
@@ -182,9 +180,9 @@
     suspend fun registerContentObserverForUser(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserverForUser-B")) {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
         }
     }
@@ -199,7 +197,7 @@
         settingsObserver: ContentObserver,
         userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-D")).launch {
+        settingsScope.launch("registerContentObserverForUserAsync-B") {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
         }
 
@@ -216,7 +214,7 @@
         userHandle: Int,
         @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-E")).launch {
+        settingsScope.launch("registerContentObserverForUserAsync-C") {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
             registered.run()
         }
@@ -231,13 +229,13 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
         registerContentObserverForUserSync(
             getUriFor(name),
             notifyForDescendants,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -252,14 +250,14 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserverForUser-C")) {
             registerContentObserverForUserSync(
                 name,
                 notifyForDescendants,
                 settingsObserver,
-                userHandle
+                userHandle,
             )
         }
     }
@@ -275,7 +273,7 @@
         settingsObserver: ContentObserver,
         userHandle: Int,
     ) {
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-F")).launch {
+        settingsScope.launch("registerContentObserverForUserAsync-D") {
             registerContentObserverForUserSync(
                 getUriFor(name),
                 notifyForDescendants,
@@ -291,7 +289,7 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
         trace({ "USP#registerObserver#[$uri]" }) {
             getContentResolver()
@@ -299,7 +297,7 @@
                     uri,
                     notifyForDescendants,
                     settingsObserver,
-                    getRealUserHandle(userHandle)
+                    getRealUserHandle(userHandle),
                 )
             Unit
         }
@@ -316,14 +314,14 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        withContext(backgroundDispatcher) {
+        withContext(settingsDispatcherContext("registerContentObserverForUser-D")) {
             registerContentObserverForUserSync(
                 uri,
                 notifyForDescendants,
                 settingsObserver,
-                getRealUserHandle(userHandle)
+                getRealUserHandle(userHandle),
             )
         }
     }
@@ -339,7 +337,7 @@
         settingsObserver: ContentObserver,
         userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-G")).launch {
+        settingsScope.launch("registerContentObserverForUserAsync-E") {
             registerContentObserverForUserSync(
                 uri,
                 notifyForDescendants,
@@ -385,7 +383,7 @@
         tag: String?,
         makeDefault: Boolean,
         @UserIdInt userHandle: Int,
-        overrideableByRestore: Boolean
+        overrideableByRestore: Boolean,
     ): Boolean
 
     override fun getInt(name: String, default: Int): Int {
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/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
deleted file mode 100644
index 3c60784..0000000
--- a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml
+++ /dev/null
@@ -1,23 +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.
--->
-
-<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>
diff --git a/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml
new file mode 100644
index 0000000..a8d4d2e
--- /dev/null
+++ b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center"
+    android:paddingStart="@dimen/dialog_side_padding"
+    android:paddingEnd="@dimen/dialog_side_padding"
+    android:paddingTop="@dimen/dialog_top_padding"
+    android:paddingBottom="@dimen/dialog_bottom_padding">
+
+    <androidx.cardview.widget.CardView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:cardElevation="0dp"
+        app:cardCornerRadius="28dp"
+        app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
+
+        <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
+            android:id="@+id/rear_display_folded_animation"
+            android:importantForAccessibility="no"
+            android:layout_width="@dimen/rear_display_animation_width_opened"
+            android:layout_height="@dimen/rear_display_animation_height_opened"
+            android:layout_gravity="center"
+            android:contentDescription="@string/rear_display_accessibility_unfolded_animation"
+            android:scaleType="fitXY"
+            app:lottie_rawRes="@raw/rear_display_turnaround"
+            app:lottie_autoPlay="true"
+            app:lottie_repeatMode="reverse"/>
+    </androidx.cardview.widget.CardView>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_unfolded_front_screen_on"
+        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        android:lineSpacingExtra="2sp"
+        android:translationY="-1.24sp"
+        android:gravity="center_horizontal" />
+
+    <!-- Buttons -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:layout_marginTop="36dp">
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"/>
+        <TextView
+            android:id="@+id/button_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="0"
+            android:layout_gravity="start"
+            android:text="@string/cancel"
+            style="@style/Widget.Dialog.Button.BorderButton" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
index a313833..4b2f45f 100644
--- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
@@ -27,12 +27,13 @@
         android:layout_height="@dimen/conversation_single_line_face_pile_size"
         android:paddingHorizontal="16dp"
     >
-        <ImageView
+        <com.android.internal.widget.CachingIconView
             android:id="@*android:id/conversation_icon"
             android:layout_width="@dimen/conversation_single_line_avatar_size"
             android:layout_height="@dimen/conversation_single_line_avatar_size"
             android:layout_gravity="center_vertical|end"
-        />
+            android:scaleType="centerCrop"
+            />
 
         <ViewStub
             android:id="@*android:id/conversation_face_pile"
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid.xml b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
new file mode 100644
index 0000000..8c34cd4
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid.xml
@@ -0,0 +1,42 @@
+<?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 LinearLayout -->
+<com.android.systemui.statusbar.notification.row.HybridNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="bottom|start"
+    android:paddingStart="@*android:dimen/notification_2025_content_margin_start"
+    android:paddingEnd="12dp">
+    <TextView
+        android:id="@+id/notification_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+        android:paddingEnd="4dp"
+    />
+    <TextView
+        android:id="@+id/notification_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:paddingEnd="4dp"
+        style="@*android:style/Widget.DeviceDefault.Notification.Text"
+    />
+</com.android.systemui.statusbar.notification.row.HybridNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
new file mode 100644
index 0000000..ff5d9d3
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml
@@ -0,0 +1,74 @@
+<?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 LinearLayout -->
+<com.android.systemui.statusbar.notification.row.HybridConversationNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical|start"
+    android:paddingStart="@*android:dimen/notification_2025_content_margin_start"
+    android:paddingEnd="12dp">
+
+    <FrameLayout
+        android:layout_width="@dimen/notification_2025_single_line_face_pile_size"
+        android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
+        android:layout_marginEnd="8dp"
+    >
+        <ImageView
+            android:id="@*android:id/conversation_icon"
+            android:layout_width="@dimen/notification_2025_single_line_avatar_size"
+            android:layout_height="@dimen/notification_2025_single_line_avatar_size"
+            android:layout_gravity="center_vertical|end"
+        />
+
+        <ViewStub
+            android:id="@*android:id/conversation_face_pile"
+            android:layout="@*android:layout/conversation_face_pile_layout"
+            android:layout_width="@dimen/notification_2025_single_line_face_pile_size"
+            android:layout_height="@dimen/notification_2025_single_line_face_pile_size"
+            android:layout_gravity="center_vertical|end"
+        />
+    </FrameLayout>
+
+    <TextView
+        android:id="@+id/notification_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:paddingEnd="4dp"
+        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
+    />
+
+    <TextView
+        android:id="@+id/conversation_notification_sender"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:paddingEnd="4dp"
+        style="@*android:style/Widget.DeviceDefault.Notification.Text"
+    />
+
+    <TextView
+        android:id="@+id/notification_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:paddingEnd="4dp"
+        style="@*android:style/Widget.DeviceDefault.Notification.Text"
+    />
+</com.android.systemui.statusbar.notification.row.HybridConversationNotificationView>
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index d0a1ce8..215e4e4 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -55,9 +55,14 @@
         />
 
         <!-- Shows generic text. -->
+        <!-- Since there's so little room in the status bar chip area, don't ellipsize the text and
+             instead just fade it out a bit at the end. -->
         <TextView
             android:id="@+id/ongoing_activity_chip_text"
             style="@style/StatusBar.Chip.Text"
+            android:ellipsize="none"
+            android:requiresFadingEdge="horizontal"
+            android:fadingEdgeLength="@dimen/ongoing_activity_chip_text_fading_edge_length"
             android:visibility="gone"
             />
 
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 7af0057..580f6d3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -788,6 +788,18 @@
     <!-- Size of an avatar shown on one-line (children of a group) conversation notifications -->
     <dimen name="conversation_single_line_avatar_size">24dp</dimen>
 
+    <!-- Size of the face pile shown on one-line (children of a group) conversation notifications
+         (2025 redesign version) -->
+    <dimen name="notification_2025_single_line_face_pile_size">16dp</dimen>
+
+    <!-- Size of the avatars within a face pile shown on one-line (children of a group) conversation
+         notifications (2025 redesign version) -->
+    <dimen name="notification_2025_single_line_face_pile_avatar_size">11dp</dimen>
+
+    <!-- Size of an avatar shown on one-line (children of a group) conversation notifications
+         (2025 redesign version) -->
+    <dimen name="notification_2025_single_line_avatar_size">16dp</dimen>
+
     <!-- Border width for avatars in the face pile shown on one-line (children of a group) conversation notifications -->
     <dimen name="conversation_single_line_face_pile_protection_width">1dp</dimen>
 
@@ -1749,6 +1761,7 @@
     <dimen name="ongoing_activity_chip_icon_text_padding">4dp</dimen>
     <!-- The end padding for the timer text view. Only used if an embedded padding icon is used. -->
     <dimen name="ongoing_activity_chip_text_end_padding_for_embedded_padding_icon">6dp</dimen>
+    <dimen name="ongoing_activity_chip_text_fading_edge_length">12dp</dimen>
     <dimen name="ongoing_activity_chip_corner_radius">28dp</dimen>
 
     <!-- Status bar user chip -->
@@ -1955,8 +1968,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>
@@ -2060,26 +2071,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 b45aadd..245ba0a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3568,6 +3568,8 @@
     <string name="rear_display_accessibility_folded_animation">Foldable device being unfolded</string>
     <!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] -->
     <string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string>
+    <!-- Text for a dialog telling the user that the front screen is turned on. [CHAR_LIMIT=NONE] -->
+    <string name="rear_display_unfolded_front_screen_on">Front screen turned on</string>
 
     <!-- QuickSettings: Additional label for the auto-rotation quicksettings tile indicating that the setting corresponds to the folded posture for a foldable device [CHAR LIMIT=32] -->
     <string name="quick_settings_rotation_posture_folded">folded</string>
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/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/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 4e0e112..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
 
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 ccff230..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")
 
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/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 1a56541..400d097 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.deviceentry.domain.interactor
 
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.policy.IKeyguardDismissCallback
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
@@ -43,7 +44,6 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 /**
  * Hosts application business logic related to device entry.
@@ -174,6 +174,14 @@
     }
 
     /**
+     * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
+     * dismissed once the authentication challenge is completed. For example, completing a biometric
+     * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
+     * lockscreen.
+     */
+    val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
+
+    /**
      * Attempt to enter the device and dismiss the lockscreen. If authentication is required to
      * unlock the device it will transition to bouncer.
      *
@@ -238,11 +246,8 @@
         isLockscreenEnabled()
     }
 
-    /**
-     * Whether lockscreen bypass is enabled. When enabled, the lockscreen will be automatically
-     * dismissed once the authentication challenge is completed. For example, completing a biometric
-     * authentication challenge via face unlock or fingerprint sensor can automatically bypass the
-     * lockscreen.
-     */
-    val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
+    /** Locks the device instantly. */
+    fun lockNow() {
+        deviceUnlockedInteractor.lockNow()
+    }
 }
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 35eed5e..7d684ca 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
@@ -43,6 +43,7 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
@@ -57,6 +58,7 @@
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.receiveAsFlow
 import kotlinx.coroutines.launch
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -178,6 +180,8 @@
     val deviceUnlockStatus: StateFlow<DeviceUnlockStatus> =
         repository.deviceUnlockStatus.asStateFlow()
 
+    private val lockNowRequests = Channel<Unit>()
+
     override suspend fun onActivated(): Nothing {
         authenticationInteractor.authenticationMethod.collectLatest { authMethod ->
             if (!authMethod.isSecure) {
@@ -196,6 +200,11 @@
         awaitCancellation()
     }
 
+    /** Locks the device instantly. */
+    fun lockNow() {
+        lockNowRequests.trySend(Unit)
+    }
+
     private suspend fun handleLockAndUnlockEvents() {
         try {
             Log.d(TAG, "started watching for lock and unlock events")
@@ -225,10 +234,12 @@
                     .map { (isAsleep, lastSleepReason) ->
                         if (isAsleep) {
                             if (
-                                lastSleepReason == WakeSleepReason.POWER_BUTTON &&
+                                (lastSleepReason == WakeSleepReason.POWER_BUTTON) &&
                                     authenticationInteractor.getPowerButtonInstantlyLocks()
                             ) {
                                 LockImmediately("locked instantly from power button")
+                            } else if (lastSleepReason == WakeSleepReason.SLEEP_BUTTON) {
+                                LockImmediately("locked instantly from sleep button")
                             } else {
                                 LockWithDelay("entering sleep")
                             }
@@ -256,6 +267,7 @@
                         emptyFlow()
                     }
                 },
+                lockNowRequests.receiveAsFlow().map { LockImmediately("lockNow") },
             )
             .collectLatest(::onLockEvent)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
index 589dbf9..e862525 100644
--- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -30,6 +30,8 @@
 import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractorImpl
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import dagger.Binds
 import dagger.Lazy
@@ -46,6 +48,11 @@
         provider: ConnectedDisplayInteractorImpl
     ): ConnectedDisplayInteractor
 
+    @Binds
+    fun bindRearDisplayStateInteractor(
+        provider: RearDisplayStateInteractorImpl
+    ): RearDisplayStateInteractor
+
     @Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
index 1da5351..29044d0 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt
@@ -20,6 +20,7 @@
 import android.hardware.devicestate.DeviceState as PlatformDeviceState
 import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT
 import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY
+import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
@@ -49,6 +50,15 @@
         UNFOLDED,
         /** Device state that corresponds to the device being in rear display mode */
         REAR_DISPLAY,
+        /**
+         * Device state that corresponds to the device being in rear display mode with the inner
+         * display showing a system-provided affordance to cancel the mode.
+         *
+         * TODO(b/371095273): This state will be removed after the RDM_V2 flag lifecycle is complete
+         *   at which point the REAR_DISPLAY state will be the will be the new and only rear display
+         *   mode.
+         */
+        REAR_DISPLAY_OUTER_DEFAULT,
         /** Device state in that corresponds to the device being in concurrent display mode */
         CONCURRENT_DISPLAY,
         /** Device state in none of the other arrays. */
@@ -62,7 +72,7 @@
     val context: Context,
     val deviceStateManager: DeviceStateManager,
     @Background bgScope: CoroutineScope,
-    @Background executor: Executor
+    @Background executor: Executor,
 ) : DeviceStateRepository {
 
     override val state: StateFlow<DeviceState> =
@@ -105,6 +115,12 @@
      */
     private fun PlatformDeviceState.toDeviceStateEnum(): DeviceState {
         return when {
+            hasProperties(
+                PROPERTY_FEATURE_REAR_DISPLAY,
+                PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT,
+            ) -> {
+                DeviceState.REAR_DISPLAY_OUTER_DEFAULT
+            }
             hasProperty(PROPERTY_FEATURE_REAR_DISPLAY) -> DeviceState.REAR_DISPLAY
             hasProperty(PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT) -> {
                 DeviceState.CONCURRENT_DISPLAY
@@ -112,7 +128,7 @@
             hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) -> DeviceState.FOLDED
             hasProperties(
                 PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
-                PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN
+                PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN,
             ) -> DeviceState.HALF_FOLDED
             hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) -> {
                 DeviceState.UNFOLDED
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt
new file mode 100644
index 0000000..b743377
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.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.systemui.display.domain.interactor
+
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DeviceStateRepository
+import com.android.systemui.display.data.repository.DisplayRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combineTransform
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+
+/** Provides information about the status of Rear Display Mode. */
+interface RearDisplayStateInteractor {
+
+    /** A flow notifying the subscriber of Rear Display state changes */
+    val state: Flow<State>
+
+    sealed class State {
+        /** Indicates that the rear display is disabled */
+        data object Disabled : State()
+
+        /**
+         * Indicates that the device is in Rear Display Mode, and that the inner display is ready to
+         * show a system-provided affordance allowing the user to cancel out of the Rear Display
+         * Mode.
+         */
+        data class Enabled(val innerDisplay: Display) : State()
+    }
+}
+
+@SysUISingleton
+class RearDisplayStateInteractorImpl
+@Inject
+constructor(
+    displayRepository: DisplayRepository,
+    deviceStateRepository: DeviceStateRepository,
+    @Background backgroundCoroutineDispatcher: CoroutineDispatcher,
+) : RearDisplayStateInteractor {
+
+    override val state: Flow<RearDisplayStateInteractor.State> =
+        deviceStateRepository.state
+            .combineTransform(displayRepository.displays) { state, displays ->
+                val innerDisplay = displays.find { it.flags and Display.FLAG_REAR != 0 }
+
+                if (state != DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT) {
+                    emit(RearDisplayStateInteractor.State.Disabled)
+                } else if (innerDisplay != null) {
+                    emit(RearDisplayStateInteractor.State.Enabled(innerDisplay))
+                }
+            }
+            .distinctUntilChanged()
+            .flowOn(backgroundCoroutineDispatcher)
+}
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/keyboard/shortcut/ShortcutHelperModule.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
index 7b3380a..1af7340 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ShortcutHelperModule.kt
@@ -18,6 +18,9 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.Flags.keyboardShortcutHelperRewrite
+import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
 import com.android.systemui.keyboard.shortcut.data.source.AppCategoriesShortcutsSource
 import com.android.systemui.keyboard.shortcut.data.source.CurrentAppShortcutsSource
@@ -27,6 +30,8 @@
 import com.android.systemui.keyboard.shortcut.data.source.SystemShortcutsSource
 import com.android.systemui.keyboard.shortcut.qualifiers.AppCategoriesShortcuts
 import com.android.systemui.keyboard.shortcut.qualifiers.CurrentAppShortcuts
+import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
+import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
 import com.android.systemui.keyboard.shortcut.qualifiers.InputShortcuts
 import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
 import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
@@ -63,6 +68,18 @@
         impl: AppCategoriesShortcutsSource
     ): KeyboardShortcutGroupsSource
 
+    @Binds
+    @DefaultShortcutCategories
+    fun defaultShortcutCategoriesRepository(
+        impl: DefaultShortcutCategoriesRepository
+    ): ShortcutCategoriesRepository
+
+    @Binds
+    @CustomShortcutCategories
+    fun customShortcutCategoriesRepository(
+        impl: CustomShortcutCategoriesRepository
+    ): ShortcutCategoriesRepository
+
     companion object {
         @Provides
         @IntoMap
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 ec1d358..da5590a 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
@@ -23,19 +23,24 @@
 import android.hardware.input.InputManager
 import android.hardware.input.InputSettings
 import android.hardware.input.KeyGestureEvent
+import com.android.systemui.Flags.shortcutHelperKeyGlyph
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup
 import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.settings.UserTracker
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
@@ -60,6 +65,8 @@
     private val inputManager: InputManager
         get() = userContext.getSystemService(INPUT_SERVICE) as InputManager
 
+    private val _selectedKeyCombination = MutableStateFlow<KeyCombination?>(null)
+
     private val activeInputDevice =
         stateRepository.state.map {
             if (it is Active) {
@@ -69,6 +76,41 @@
             }
         }
 
+    val pressedKeys =
+        _selectedKeyCombination
+            .combine(activeInputDevice) { keyCombination, inputDevice ->
+                if (inputDevice == null || keyCombination == null) {
+                    return@combine emptyList()
+                } else {
+                    val keyGlyphMap =
+                        if (shortcutHelperKeyGlyph()) {
+                            inputManager.getKeyGlyphMap(inputDevice.id)
+                        } else null
+                    val modifiers =
+                        shortcutCategoriesUtils.toShortcutModifierKeys(
+                            keyCombination.modifiers,
+                            keyGlyphMap,
+                        )
+                    val triggerKey =
+                        keyCombination.keyCode?.let {
+                            shortcutCategoriesUtils.toShortcutKey(
+                                keyGlyphMap,
+                                inputDevice.keyCharacterMap,
+                                keyCode = it,
+                            )
+                        }
+                    val keys = mutableListOf<ShortcutKey>()
+                    modifiers?.let { keys += it }
+                    triggerKey?.let { keys += it }
+                    return@combine keys
+                }
+            }
+            .stateIn(
+                scope = backgroundScope,
+                started = SharingStarted.Lazily,
+                initialValue = emptyList(),
+            )
+
     override val categories: Flow<List<ShortcutCategory>> =
         activeInputDevice
             .map { inputDevice ->
@@ -104,6 +146,10 @@
                 started = SharingStarted.Lazily,
             )
 
+    fun updateUserKeyCombination(keyCombination: KeyCombination?) {
+        _selectedKeyCombination.value = keyCombination
+    }
+
     private fun toInternalGroupSources(
         inputGestures: List<InputGestureData>
     ): List<InternalGroupsSource> {
@@ -148,7 +194,7 @@
     private fun fetchGroupLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        InputGestures.gestureToInternalKeyboardShortcutGroupLabelMap[keyGestureType]?.let {
+        InputGestures.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let {
             return context.getString(it)
         } ?: return null
     }
@@ -156,7 +202,7 @@
     private fun fetchShortcutInfoLabelByGestureType(
         @KeyGestureEvent.KeyGestureType keyGestureType: Int
     ): String? {
-        InputGestures.gestureToInternalKeyboardShortcutInfoLabelMap[keyGestureType]?.let {
+        InputGestures.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let {
             return context.getString(it)
         } ?: return null
     }
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 90be988..7bb294d 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
@@ -81,7 +81,7 @@
             KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to AppCategories,
         )
 
-    val gestureToInternalKeyboardShortcutGroupLabelMap =
+    val gestureToInternalKeyboardShortcutGroupLabelResIdMap =
         mapOf(
             // System Category
             KEY_GESTURE_TYPE_HOME to R.string.shortcut_helper_category_system_controls,
@@ -129,7 +129,7 @@
                 R.string.keyboard_shortcut_group_applications,
         )
 
-    val gestureToInternalKeyboardShortcutInfoLabelMap =
+    val gestureToInternalKeyboardShortcutInfoLabelResIdMap =
         mapOf(
             // System Category
             KEY_GESTURE_TYPE_HOME to R.string.group_system_access_home_screen,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
index 899fd15..3988d1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutCategoriesUtils.kt
@@ -24,6 +24,7 @@
 import android.view.InputDevice
 import android.view.KeyCharacterMap
 import android.view.KeyEvent
+import android.view.KeyEvent.META_META_ON
 import com.android.systemui.Flags.shortcutHelperKeyGlyph
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup
@@ -92,7 +93,7 @@
                 }
                 .filter { it.shortcuts.isNotEmpty() }
         return if (subCategories.isEmpty()) {
-            Log.wtf(TAG, "Empty sub categories after converting $shortcutGroups")
+            Log.w(TAG, "Empty sub categories after converting $shortcutGroups")
             null
         } else {
             ShortcutCategory(type, subCategories)
@@ -161,7 +162,7 @@
         }
         if (remainingModifiers != 0) {
             // There is a remaining modifier we don't support
-            Log.wtf(TAG, "Unsupported modifiers remaining: $remainingModifiers")
+            Log.w(TAG, "Unsupported modifiers remaining: $remainingModifiers")
             return null
         }
         if (info.keycode != 0 || info.baseCharacter > Char.MIN_VALUE) {
@@ -170,21 +171,32 @@
                     ?: return null
         }
         if (keys.isEmpty()) {
-            Log.wtf(TAG, "No keys for $info")
+            Log.w(TAG, "No keys for $info")
             return null
         }
         return ShortcutCommand(keys = keys, isCustom = info.isCustomShortcut)
     }
 
+    fun toShortcutModifierKeys(modifiers: Int, keyGlyphMap: KeyGlyphMap?): List<ShortcutKey>? {
+        val keys: MutableList<ShortcutKey> = mutableListOf()
+        var remainingModifiers = modifiers
+        SUPPORTED_MODIFIERS.forEach { supportedModifier ->
+            if ((supportedModifier and remainingModifiers) != 0) {
+                keys += toShortcutModifierKey(keyGlyphMap, supportedModifier) ?: return null
+                remainingModifiers = remainingModifiers and supportedModifier.inv()
+            }
+        }
+        return keys
+    }
+
     private fun toShortcutModifierKey(keyGlyphMap: KeyGlyphMap?, modifierMask: Int): ShortcutKey? {
         val modifierDrawable = keyGlyphMap?.getDrawableForModifierState(context, modifierMask)
         if (modifierDrawable != null) {
             return ShortcutKey.Icon.DrawableIcon(drawable = modifierDrawable)
         }
 
-        val iconResId = ShortcutHelperKeys.keyIcons[modifierMask]
-        if (iconResId != null) {
-            return ShortcutKey.Icon.ResIdIcon(iconResId)
+        if (modifierMask == META_META_ON) {
+            return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.metaModifierIconResId)
         }
 
         val modifierLabel = ShortcutHelperKeys.modifierLabels[modifierMask]
@@ -195,7 +207,7 @@
         return null
     }
 
-    private fun toShortcutKey(
+    fun toShortcutKey(
         keyGlyphMap: KeyGlyphMap?,
         keyCharacterMap: KeyCharacterMap,
         keyCode: Int,
@@ -222,7 +234,7 @@
         if (displayLabelCharacter.code != 0) {
             return ShortcutKey.Text(displayLabelCharacter.toString())
         }
-        Log.wtf(TAG, "Couldn't find label or icon for key: $keyCode")
+        Log.w(TAG, "Couldn't find label or icon for key: $keyCode")
         return null
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
index 288efa2..e47b33f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt
@@ -116,9 +116,10 @@
 
 object ShortcutHelperKeys {
 
+    val metaModifierIconResId = R.drawable.ic_ksh_key_meta
+
     val keyIcons =
         mapOf(
-            META_META_ON to R.drawable.ic_ksh_key_meta,
             KEYCODE_BACK to R.drawable.ic_arrow_back_2,
             KEYCODE_HOME to R.drawable.ic_radio_button_unchecked,
             KEYCODE_RECENT_APPS to R.drawable.ic_check_box_outline_blank,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
index 85d2214..aad55dc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutCustomizationInteractor.kt
@@ -16,13 +16,22 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
-import android.view.KeyEvent.META_META_ON
+import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository
 import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
+import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import javax.inject.Inject
 
-class ShortcutCustomizationInteractor @Inject constructor() {
+class ShortcutCustomizationInteractor
+@Inject
+constructor(private val customShortcutRepository: CustomShortcutCategoriesRepository) {
+    val pressedKeys = customShortcutRepository.pressedKeys
+
+    fun updateUserSelectedKeyCombination(keyCombination: KeyCombination?) {
+        customShortcutRepository.updateUserKeyCombination(keyCombination)
+    }
+
     fun getDefaultCustomShortcutModifierKey(): ShortcutKey.Icon.ResIdIcon {
-        return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.keyIcons[META_META_ON]!!)
+        return ShortcutKey.Icon.ResIdIcon(ShortcutHelperKeys.metaModifierIconResId)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index 39fc27d..0381eae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -16,37 +16,66 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
+import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
+import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
+import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
 import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
 
 @SysUISingleton
 class ShortcutHelperCategoriesInteractor
 @Inject
-constructor(categoriesRepository: DefaultShortcutCategoriesRepository) {
-
+constructor(
+    @DefaultShortcutCategories defaultCategoriesRepository: ShortcutCategoriesRepository,
+    @CustomShortcutCategories customCategoriesRepositoryLazy: Lazy<ShortcutCategoriesRepository>,
+) {
     val shortcutCategories: Flow<List<ShortcutCategory>> =
-        categoriesRepository.categories.map { categories ->
-            categories.map { category -> groupSubCategoriesInCategory(category) }
+        defaultCategoriesRepository.categories.combine(
+            if (keyboardShortcutHelperShortcutCustomizer()) {
+                customCategoriesRepositoryLazy.get().categories
+            } else {
+                flowOf(emptyList())
+            }
+        ) { defaultShortcutCategories, customShortcutCategories ->
+            groupCategories(defaultShortcutCategories + customShortcutCategories)
         }
 
-    private fun groupSubCategoriesInCategory(shortcutCategory: ShortcutCategory): ShortcutCategory {
-        val subCategoriesWithGroupedShortcuts =
-            shortcutCategory.subCategories.map {
-                ShortcutSubCategory(
-                    label = it.label,
-                    shortcuts = groupShortcutsInSubcategory(it.shortcuts),
+    private fun groupCategories(
+        shortcutCategories: List<ShortcutCategory>
+    ): List<ShortcutCategory> {
+        return shortcutCategories
+            .groupBy { it.type }
+            .entries
+            .map { (categoryType, groupedCategories) ->
+                ShortcutCategory(
+                    type = categoryType,
+                    subCategories =
+                        groupSubCategories(groupedCategories.flatMap { it.subCategories }),
                 )
             }
-        return ShortcutCategory(
-            type = shortcutCategory.type,
-            subCategories = subCategoriesWithGroupedShortcuts,
-        )
+    }
+
+    private fun groupSubCategories(
+        subCategories: List<ShortcutSubCategory>
+    ): List<ShortcutSubCategory> {
+        return subCategories
+            .groupBy { it.label }
+            .entries
+            .map { (label, groupedSubcategories) ->
+                ShortcutSubCategory(
+                    label = label,
+                    shortcuts =
+                        groupShortcutsInSubcategory(groupedSubcategories.flatMap { it.shortcuts }),
+                )
+            }
     }
 
     private fun groupShortcutsInSubcategory(shortcuts: List<Shortcut>) =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt
new file mode 100644
index 0000000..8acb9ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/CustomShortcutCategories.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.qualifiers
+
+import javax.inject.Qualifier
+
+@Qualifier annotation class CustomShortcutCategories
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt
new file mode 100644
index 0000000..f94e10d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/qualifiers/DefaultShortcutCategories.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.qualifiers
+
+import javax.inject.Qualifier
+
+@Qualifier annotation class DefaultShortcutCategories
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt
new file mode 100644
index 0000000..5e4031b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/KeyCombination.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.shared.model
+
+data class KeyCombination(val modifiers: Int, val keyCode: Int?)
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 41e6929..b6b5d17 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
@@ -72,6 +72,7 @@
 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.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -90,15 +91,18 @@
 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
 import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.isTraversalGroup
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
 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
@@ -377,15 +381,19 @@
 
     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 (isCustomizing) {
-                    DoneButton(onClick = { isCustomizing = 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 = { isCustomizing = true })
+                    Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp))
                 }
             }
         }
@@ -393,7 +401,7 @@
         Row(Modifier.fillMaxWidth()) {
             StartSidePanel(
                 onSearchQueryChanged = onSearchQueryChanged,
-                modifier = Modifier.width(240.dp),
+                modifier = Modifier.width(240.dp).semantics { isTraversalGroup = true },
                 categories = categories,
                 onKeyboardSettingsClicked = onKeyboardSettingsClicked,
                 selectedCategory = selectedCategoryType,
@@ -402,7 +410,7 @@
             Spacer(modifier = Modifier.width(24.dp))
             EndSidePanel(
                 searchQuery,
-                Modifier.fillMaxSize().padding(top = 8.dp),
+                Modifier.fillMaxSize().padding(top = 8.dp).semantics { isTraversalGroup = true },
                 selectedCategory,
                 isCustomizing = isCustomizing,
                 onCustomizationRequested = onCustomizationRequested,
@@ -550,7 +558,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,
         ) {
@@ -561,7 +569,7 @@
         }
         Spacer(modifier = Modifier.width(24.dp))
         ShortcutKeyCombinations(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(.666f),
             shortcut = shortcut,
             isCustomizing = isCustomizing,
             onAddShortcutRequested = { onCustomizationRequested(shortcut.label) },
@@ -791,16 +799,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,
+            )
+        }
     }
 }
 
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/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index 912bfe9..08fd0af8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -123,7 +123,7 @@
                         userContext.packageManager.getApplicationIcon(type.packageName)
                     IconSource(painter = DrawablePainter(drawable = iconDrawable))
                 } catch (e: NameNotFoundException) {
-                    Log.wtf(
+                    Log.w(
                         "ShortcutHelperViewModel",
                         "Package not found when retrieving icon for ${type.packageName}",
                     )
@@ -153,7 +153,7 @@
                 packageManagerForUser.getApplicationInfo(type.packageName, /* flags= */ 0)
             return packageManagerForUser.getApplicationLabel(currentAppInfo).toString()
         } catch (e: NameNotFoundException) {
-            Log.wtf(
+            Log.w(
                 "ShortcutHelperViewModel",
                 "Package Not found when retrieving Label for ${type.packageName}",
             )
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 32c2bc7..7097c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -662,7 +662,9 @@
             trace("doKeyguardTimeout");
             checkPermission();
 
-            if (KeyguardWmStateRefactor.isEnabled()) {
+            if (SceneContainerFlag.isEnabled()) {
+                mDeviceEntryInteractorLazy.get().lockNow();
+            } else if (KeyguardWmStateRefactor.isEnabled()) {
                 mKeyguardLockWhileAwakeInteractor.onKeyguardServiceDoKeyguardTimeout(options);
             }
 
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/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/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 283651d..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
@@ -144,7 +144,7 @@
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue = clockRegistry.createCurrentClock(),
+                initialValue = null,
             )
 
     override val previewClock: Flow<ClockController> =
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/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index 08c3f15..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
@@ -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 c009720..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
@@ -221,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/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 7ad2ec5..d54d411 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
@@ -124,7 +124,7 @@
                 ConstraintSet.START,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.START,
-                horizontalPaddingStart
+                horizontalPaddingStart,
             )
 
             // migrate addSmartspaceView from KeyguardClockSwitchController
@@ -135,15 +135,15 @@
                 ConstraintSet.START,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.START,
-                horizontalPaddingStart
+                horizontalPaddingStart,
             )
             connect(
                 sharedR.id.bc_smartspace_view,
                 ConstraintSet.END,
-                if (keyguardClockViewModel.clockShouldBeCentered.value) ConstraintSet.PARENT_ID
-                else R.id.split_shade_guideline,
+                if (keyguardSmartspaceViewModel.isShadeLayoutWide.value) R.id.split_shade_guideline
+                else ConstraintSet.PARENT_ID,
                 ConstraintSet.END,
-                horizontalPaddingEnd
+                horizontalPaddingEnd,
             )
 
             if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) {
@@ -152,7 +152,7 @@
                     sharedR.id.date_smartspace_view,
                     ConstraintSet.BOTTOM,
                     sharedR.id.bc_smartspace_view,
-                    ConstraintSet.TOP
+                    ConstraintSet.TOP,
                 )
             } else {
                 clear(sharedR.id.date_smartspace_view, ConstraintSet.BOTTOM)
@@ -160,13 +160,13 @@
                     sharedR.id.date_smartspace_view,
                     ConstraintSet.TOP,
                     customR.id.lockscreen_clock_view,
-                    ConstraintSet.BOTTOM
+                    ConstraintSet.BOTTOM,
                 )
                 connect(
                     sharedR.id.bc_smartspace_view,
                     ConstraintSet.TOP,
                     sharedR.id.date_smartspace_view,
-                    ConstraintSet.BOTTOM
+                    ConstraintSet.BOTTOM,
                 )
             }
 
@@ -174,10 +174,7 @@
                 R.id.smart_space_barrier_bottom,
                 Barrier.BOTTOM,
                 0,
-                *intArrayOf(
-                    sharedR.id.bc_smartspace_view,
-                    sharedR.id.date_smartspace_view,
-                )
+                *intArrayOf(sharedR.id.bc_smartspace_view, sharedR.id.date_smartspace_view),
             )
         }
         updateVisibility(constraintSet)
@@ -212,7 +209,7 @@
             setVisibility(sharedR.id.weather_smartspace_view, weatherVisibility)
             setAlpha(
                 sharedR.id.weather_smartspace_view,
-                if (weatherVisibility == View.VISIBLE) 1f else 0f
+                if (weatherVisibility == View.VISIBLE) 1f else 0f,
             )
             val dateVisibility =
                 if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) ConstraintSet.GONE
@@ -220,7 +217,7 @@
             setVisibility(sharedR.id.date_smartspace_view, dateVisibility)
             setAlpha(
                 sharedR.id.date_smartspace_view,
-                if (dateVisibility == ConstraintSet.VISIBLE) 1f else 0f
+                if (dateVisibility == ConstraintSet.VISIBLE) 1f else 0f,
             )
         }
     }
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 0782846..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,6 +28,7 @@
 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
@@ -42,7 +43,7 @@
 constructor(
     @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
 
@@ -62,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/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt
index e30ddc6..3266dc4 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,10 +17,12 @@
 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
 import com.android.systemui.res.R
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -38,6 +40,7 @@
     smartspaceController: LockscreenSmartspaceController,
     keyguardClockViewModel: KeyguardClockViewModel,
     smartspaceInteractor: KeyguardSmartspaceInteractor,
+    shadeInteractor: ShadeInteractor,
 ) {
     /** Whether the smartspace section is available in the build. */
     val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled
@@ -59,10 +62,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 +78,7 @@
                         clockIncludesCustomWeatherDisplay =
                             keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
                         isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
-                    )
+                    ),
             )
 
     private fun isWeatherVisible(
@@ -89,15 +91,17 @@
     /* trigger clock and smartspace constraints change when smartspace appears */
     val bcSmartspaceVisibility: StateFlow<Int> = smartspaceInteractor.bcSmartspaceVisibility
 
+    val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide
+
     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/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 4c21da5..8097d95 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -32,8 +32,6 @@
 import com.android.systemui.qs.QSFragmentLegacy;
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
 import com.android.systemui.qs.pipeline.shared.TileSpec;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.util.Compile;
 import com.android.systemui.util.wakelock.WakeLockLog;
 
 import dagger.Lazy;
@@ -56,61 +54,6 @@
         return factory.create("DozeLog", 150);
     }
 
-    /** Provides a logging buffer for all logs related to the data layer of notifications. */
-    @Provides
-    @SysUISingleton
-    @NotificationLog
-    public static LogBuffer provideNotificationsLogBuffer(
-            LogBufferFactory factory,
-            NotifPipelineFlags notifPipelineFlags) {
-        int maxSize = 1000;
-        if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) {
-            maxSize *= 10;
-        }
-        return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */);
-    }
-
-    /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
-    @Provides
-    @SysUISingleton
-    @NotificationLockscreenLog
-    public static LogBuffer provideNotificationLockScreenLogBuffer(
-            LogBufferFactory factory) {
-        return factory.create("NotifLockscreenLog", 50, false /* systrace */);
-    }
-
-    /** Provides a logging buffer for logs related to heads up presentation of notifications. */
-    @Provides
-    @SysUISingleton
-    @NotificationHeadsUpLog
-    public static LogBuffer provideNotificationHeadsUpLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifHeadsUpLog", 1000);
-    }
-
-    /** Provides a logging buffer for logs related to inflation of notifications. */
-    @Provides
-    @SysUISingleton
-    @NotifInflationLog
-    public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifInflationLog", 250);
-    }
-
-    /** Provides a logging buffer for notification interruption calculations. */
-    @Provides
-    @SysUISingleton
-    @NotificationInterruptLog
-    public static LogBuffer provideNotificationInterruptLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifInterruptLog", 100);
-    }
-
-    /** Provides a logging buffer for notification rendering events. */
-    @Provides
-    @SysUISingleton
-    @NotificationRenderLog
-    public static LogBuffer provideNotificationRenderLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifRenderLog", 100);
-    }
-
     /** Provides a logging buffer for all logs for lockscreen to shade transition events. */
     @Provides
     @SysUISingleton
@@ -119,16 +62,6 @@
         return factory.create("LSShadeTransitionLog", 50);
     }
 
-    /** */
-    @Provides
-    @SysUISingleton
-    @SensitiveNotificationProtectionLog
-    public static LogBuffer provideSensitiveNotificationProtectionLogBuffer(
-            LogBufferFactory factory
-    ) {
-        return factory.create("SensitiveNotificationProtectionLog", 10);
-    }
-
     /** Provides a logging buffer for shade window messages. */
     @Provides
     @SysUISingleton
@@ -153,30 +86,6 @@
         return factory.create("ShadeTouchLog", 500, false);
     }
 
-    /** Provides a logging buffer for all logs related to managing notification sections. */
-    @Provides
-    @SysUISingleton
-    @NotificationSectionLog
-    public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifSectionLog", 1000 /* maxSize */, false /* systrace */);
-    }
-
-    /** Provides a logging buffer for all logs related to remote input controller. */
-    @Provides
-    @SysUISingleton
-    @NotificationRemoteInputLog
-    public static LogBuffer provideNotificationRemoteInputLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */);
-    }
-
-    /** Provides a logging buffer for all logs related to notification visual stability. */
-    @Provides
-    @SysUISingleton
-    @VisualStabilityLog
-    public static LogBuffer provideVisualStabilityLogBuffer(LogBufferFactory factory) {
-        return factory.create("VisualStabilityLog", 50 /* maxSize */, false /* systrace */);
-    }
-
     /** Provides a logging buffer for all logs related to keyguard media controller. */
     @Provides
     @SysUISingleton
@@ -185,22 +94,6 @@
         return factory.create("KeyguardMediaControllerLog", 50 /* maxSize */, false /* systrace */);
     }
 
-    /** Provides a logging buffer for all logs related to unseen notifications. */
-    @Provides
-    @SysUISingleton
-    @UnseenNotificationLog
-    public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) {
-        return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */);
-    }
-
-    /** Provides a logging buffer for all logs related to the data layer of notifications. */
-    @Provides
-    @SysUISingleton
-    @NotifInteractionLog
-    public static LogBuffer provideNotifInteractionLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifInteractionLog", 50);
-    }
-
     /** Provides a logging buffer for all logs related to Quick Settings. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
index 3e947d9..7803f22 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
+++ b/packages/SystemUI/src/com/android/systemui/notetask/INoteTaskBubblesService.aidl
@@ -16,6 +16,7 @@
 
 package com.android.systemui.notetask;
 
+import com.android.systemui.notetask.NoteTaskBubbleExpandBehavior;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
@@ -25,5 +26,6 @@
 
     boolean areBubblesAvailable();
 
-    void showOrHideAppBubble(in Intent intent, in UserHandle userHandle, in Icon icon);
+    void showOrHideAppBubble(in Intent intent, in UserHandle userHandle, in Icon icon,
+     in NoteTaskBubbleExpandBehavior bubbleExpandBehavior);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl
new file mode 100644
index 0000000..86a06a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.aidl
@@ -0,0 +1,3 @@
+package com.android.systemui.notetask;
+
+parcelable NoteTaskBubbleExpandBehavior;
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.kt
new file mode 100644
index 0000000..63b38a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubbleExpandBehavior.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.systemui.notetask
+
+import android.os.Parcel
+import android.os.Parcelable
+
+enum class NoteTaskBubbleExpandBehavior : Parcelable {
+    /**
+     * The default bubble expand behavior for note task bubble: The bubble will collapse if there is
+     * already an expanded bubble, The bubble will expand if there is a collapsed bubble.
+     */
+    DEFAULT,
+    /**
+     * The special bubble expand behavior for note task bubble: The bubble will stay expanded, not
+     * collapse, if there is already an expanded bubble, The bubble will expand if there is a
+     * collapsed bubble.
+     */
+    KEEP_IF_EXPANDED;
+
+    override fun describeContents(): Int {
+        return 0
+    }
+
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(name)
+    }
+
+    companion object CREATOR : Parcelable.Creator<NoteTaskBubbleExpandBehavior> {
+        override fun createFromParcel(parcel: Parcel?): NoteTaskBubbleExpandBehavior {
+            return parcel?.readString()?.let { valueOf(it) } ?: DEFAULT
+        }
+
+        override fun newArray(size: Int) = arrayOfNulls<NoteTaskBubbleExpandBehavior>(size)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
index ec205f8..169285f 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskBubblesController.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.log.DebugLogger.debugLog
+import com.android.wm.shell.bubbles.Bubble
 import com.android.wm.shell.bubbles.Bubbles
 import java.util.Optional
 import javax.inject.Inject
@@ -48,7 +49,7 @@
 @Inject
 constructor(
     @Application private val context: Context,
-    @Background private val bgDispatcher: CoroutineDispatcher
+    @Background private val bgDispatcher: CoroutineDispatcher,
 ) {
 
     private val serviceConnector: ServiceConnector<INoteTaskBubblesService> =
@@ -57,7 +58,7 @@
             Intent(context, NoteTaskBubblesService::class.java),
             Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
             UserHandle.USER_SYSTEM,
-            INoteTaskBubblesService.Stub::asInterface
+            INoteTaskBubblesService.Stub::asInterface,
         )
 
     /** Returns whether notes app bubble is supported. */
@@ -79,11 +80,12 @@
     open suspend fun showOrHideAppBubble(
         intent: Intent,
         userHandle: UserHandle,
-        icon: Icon
+        icon: Icon,
+        bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
     ) {
         withContext(bgDispatcher) {
             serviceConnector
-                .post { it.showOrHideAppBubble(intent, userHandle, icon) }
+                .post { it.showOrHideAppBubble(intent, userHandle, icon, bubbleExpandBehavior) }
                 .whenComplete { _, error ->
                     if (error != null) {
                         debugLog(error = error) {
@@ -120,16 +122,28 @@
                 override fun showOrHideAppBubble(
                     intent: Intent,
                     userHandle: UserHandle,
-                    icon: Icon
+                    icon: Icon,
+                    bubbleExpandBehavior: NoteTaskBubbleExpandBehavior,
                 ) {
                     mOptionalBubbles.ifPresentOrElse(
-                        { bubbles -> bubbles.showOrHideAppBubble(intent, userHandle, icon) },
+                        { bubbles ->
+                            if (
+                                bubbleExpandBehavior ==
+                                    NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED &&
+                                    bubbles.isBubbleExpanded(
+                                        Bubble.getAppBubbleKeyForApp(intent.`package`, userHandle)
+                                    )
+                            ) {
+                                return@ifPresentOrElse
+                            }
+                            bubbles.showOrHideAppBubble(intent, userHandle, icon)
+                        },
                         {
                             debugLog {
                                 "Failed to show or hide bubble for intent $intent," +
                                     "user $user, and icon $icon as bubble is empty."
                             }
-                        }
+                        },
                     )
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 1fa5baa..a615963 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -84,7 +84,7 @@
     private val userTracker: UserTracker,
     private val secureSettings: SecureSettings,
     @Application private val applicationScope: CoroutineScope,
-    @Background private val bgCoroutineContext: CoroutineContext
+    @Background private val bgCoroutineContext: CoroutineContext,
 ) {
 
     @VisibleForTesting val infoReference = AtomicReference<NoteTaskInfo?>()
@@ -98,7 +98,7 @@
         if (key != Bubble.getAppBubbleKeyForApp(info.packageName, info.user)) return
 
         // Safe guard mechanism, this callback should only be called for app bubbles.
-        if (info.launchMode != NoteTaskLaunchMode.AppBubble) return
+        if (info.launchMode !is NoteTaskLaunchMode.AppBubble) return
 
         if (isExpanding) {
             debugLog { "onBubbleExpandChanged - expanding: $info" }
@@ -117,10 +117,8 @@
             } else {
                 getUserForHandlingNotesTaking(entryPoint)
             }
-        activityContext.startActivityAsUser(
-            createNotesRoleHolderSettingsIntent(),
-            user
-        )
+
+        activityContext.startActivityAsUser(createNotesRoleHolderSettingsIntent(), user)
     }
 
     /**
@@ -140,8 +138,7 @@
                 entryPoint == QUICK_AFFORDANCE -> {
                 userTracker.userProfiles
                     .firstOrNull { userManager.isManagedProfile(it.id) }
-                    ?.userHandle
-                    ?: userTracker.userHandle
+                    ?.userHandle ?: userTracker.userHandle
             }
             // On work profile devices, SysUI always run in the main user.
             else -> userTracker.userHandle
@@ -158,19 +155,14 @@
      *
      * That will let users open other apps in full screen, and take contextual notes.
      */
-    fun showNoteTask(
-        entryPoint: NoteTaskEntryPoint,
-    ) {
+    fun showNoteTask(entryPoint: NoteTaskEntryPoint) {
         if (!isEnabled) return
 
         showNoteTaskAsUser(entryPoint, getUserForHandlingNotesTaking(entryPoint))
     }
 
     /** A variant of [showNoteTask] which launches note task in the given [user]. */
-    fun showNoteTaskAsUser(
-        entryPoint: NoteTaskEntryPoint,
-        user: UserHandle,
-    ) {
+    fun showNoteTaskAsUser(entryPoint: NoteTaskEntryPoint, user: UserHandle) {
         if (!isEnabled) return
 
         applicationScope.launch("$TAG#showNoteTaskAsUser") {
@@ -178,10 +170,7 @@
         }
     }
 
-    private suspend fun awaitShowNoteTaskAsUser(
-        entryPoint: NoteTaskEntryPoint,
-        user: UserHandle,
-    ) {
+    private suspend fun awaitShowNoteTaskAsUser(entryPoint: NoteTaskEntryPoint, user: UserHandle) {
         if (!isEnabled) return
 
         if (!noteTaskBubblesController.areBubblesAvailable()) {
@@ -222,7 +211,13 @@
                     val intent = createNoteTaskIntent(info)
                     val icon =
                         Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
-                    noteTaskBubblesController.showOrHideAppBubble(intent, user, icon)
+                    noteTaskBubblesController.showOrHideAppBubble(
+                        intent,
+                        user,
+                        icon,
+                        info.launchMode.bubbleExpandBehavior,
+                    )
+
                     // App bubble logging happens on `onBubbleExpandChanged`.
                     debugLog { "onShowNoteTask - opened as app bubble: $info" }
                 }
@@ -399,8 +394,8 @@
         const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE = "extra_shortcut_badge_override_package"
 
         /** Returns notes role holder settings intent. */
-        fun createNotesRoleHolderSettingsIntent() = Intent(Intent.ACTION_MANAGE_DEFAULT_APP).
-            putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
+        fun createNotesRoleHolderSettingsIntent() =
+            Intent(Intent.ACTION_MANAGE_DEFAULT_APP).putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
index 269eb87..8319e07 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt
@@ -31,6 +31,10 @@
         if (isKeyguardLocked || entryPoint == WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE) {
             NoteTaskLaunchMode.Activity
         } else {
-            NoteTaskLaunchMode.AppBubble
+            if (entryPoint == NoteTaskEntryPoint.QS_NOTES_TILE) {
+                NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.KEEP_IF_EXPANDED)
+            } else {
+                NoteTaskLaunchMode.AppBubble(NoteTaskBubbleExpandBehavior.DEFAULT)
+            }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
index 836e103f..6c85f20 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskLaunchMode.kt
@@ -26,7 +26,8 @@
 sealed class NoteTaskLaunchMode {
 
     /** @see Bubbles.showOrHideAppBubble */
-    object AppBubble : NoteTaskLaunchMode()
+    data class AppBubble(val bubbleExpandBehavior: NoteTaskBubbleExpandBehavior) :
+        NoteTaskLaunchMode()
 
     /** @see Context.startActivity */
     object Activity : NoteTaskLaunchMode()
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index a1c5c9c..5d54656 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
 import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
 import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel
 import com.android.systemui.res.R
 import dagger.Binds
 import dagger.Module
@@ -106,12 +107,14 @@
             stateInteractor: NotesTileDataInteractor,
             userActionInteractor: NotesTileUserActionInteractor,
         ): QSTileViewModel =
-            factory.create(
-                TileSpec.create(NOTES_TILE_SPEC),
-                userActionInteractor,
-                stateInteractor,
-                mapper,
-            )
+            if (com.android.systemui.Flags.qsNewTilesFuture())
+                factory.create(
+                    TileSpec.create(NOTES_TILE_SPEC),
+                    userActionInteractor,
+                    stateInteractor,
+                    mapper,
+                )
+            else StubQSTileViewModel
 
         @Provides
         @IntoMap
@@ -120,10 +123,10 @@
             QSTileConfig(
                 tileSpec = TileSpec.create(NOTES_TILE_SPEC),
                 uiConfig =
-                QSTileUIConfig.Resource(
-                    iconRes = R.drawable.ic_qs_notes,
-                    labelRes = R.string.quick_settings_notes_label,
-                ),
+                    QSTileUIConfig.Resource(
+                        iconRes = R.drawable.ic_qs_notes,
+                        labelRes = R.string.quick_settings_notes_label,
+                    ),
                 instanceId = uiEventLogger.getNewInstanceId(),
                 category = TileCategory.UTILITIES,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
index 776a8f4..c57b53b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakeSleepReason.kt
@@ -26,6 +26,9 @@
     /** The physical power button was pressed to wake up or sleep the device. */
     POWER_BUTTON(isTouch = false, PowerManager.WAKE_REASON_POWER_BUTTON),
 
+    /** The sleep button was pressed to sleep the device. */
+    SLEEP_BUTTON(isTouch = false, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON),
+
     /** The user has tapped or double tapped to wake the screen. */
     TAP(isTouch = true, PowerManager.WAKE_REASON_TAP),
 
@@ -78,6 +81,7 @@
         fun fromPowerManagerSleepReason(reason: Int): WakeSleepReason {
             return when (reason) {
                 PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON -> POWER_BUTTON
+                PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON -> SLEEP_BUTTON
                 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT -> TIMEOUT
                 PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD -> FOLD
                 else -> OTHER
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
index 8b06942..0d464f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
 import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -48,7 +49,7 @@
 @Inject
 constructor(
     private val interactor: CurrentTilesInteractor,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,
     @Application private val scope: CoroutineScope,
     dumpManager: DumpManager,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 85bcc25..afb852a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -50,6 +50,7 @@
 import kotlin.Unit;
 import kotlin.jvm.functions.Function1;
 
+import kotlinx.coroutines.DisposableHandle;
 import kotlinx.coroutines.flow.StateFlow;
 
 import java.io.PrintWriter;
@@ -107,6 +108,8 @@
         setLayoutForMediaInScene();
     };
 
+    private DisposableHandle mJavaAdapterDisposableHandle;
+
     private boolean mLastListening;
 
     @VisibleForTesting
@@ -221,6 +224,9 @@
             mView.removeTile(record);
         }
         mRecords.clear();
+        if (mJavaAdapterDisposableHandle != null) {
+            mJavaAdapterDisposableHandle.dispose();
+        }
     }
 
     @Override
@@ -255,7 +261,7 @@
     }
 
     private void registerForMediaInteractorChanges() {
-        JavaAdapterKt.collectFlow(
+        mJavaAdapterDisposableHandle = JavaAdapterKt.collectFlow(
                 mView,
                 getMediaVisibleFlow(),
                 mMediaOrRecommendationVisibleConsumer
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index d38f849..88f0318 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -87,6 +87,7 @@
 import com.android.systemui.res.R;
 import com.android.systemui.security.data.model.SecurityModel;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.SecurityController;
 
@@ -177,7 +178,7 @@
 
     @Inject
     QSSecurityFooterUtils(
-            @Application Context context, DevicePolicyManager devicePolicyManager,
+            @ShadeDisplayAware Context context, DevicePolicyManager devicePolicyManager,
             UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
             SecurityController securityController, @Background Looper bgLooper,
             DialogTransitionAnimator dialogTransitionAnimator) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
index 676f6a4..2ec7292 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/dagger/QSFragmentComposeModule.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.qs.flags.QSComposeFragment
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.Utils
 import dagger.Module
 import dagger.Provides
@@ -34,7 +35,7 @@
         @Provides
         @SysUISingleton
         @Named(QS_USING_MEDIA_PLAYER)
-        fun providesUsingMedia(@Application context: Context): Boolean {
+        fun providesUsingMedia(@ShadeDisplayAware context: Context): Boolean {
             return QSComposeFragment.isEnabled && Utils.useQsMediaPlayer(context)
         }
     }
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/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 89f85ab..15e3499 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -43,6 +43,7 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeDisplayAware;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -69,7 +70,7 @@
 
     @Inject
     public TileQueryHelper(
-            Context context,
+            @ShadeDisplayAware Context context,
             UserTracker userTracker,
             @Main Executor mainExecutor,
             @Background Executor bgExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 564bc78..8ef6375 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
 import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.icuMessageFormat
 import javax.inject.Inject
 import javax.inject.Named
@@ -112,7 +113,7 @@
     class Factory
     @Inject
     constructor(
-        @Application private val context: Context,
+        @ShadeDisplayAware  private val context: Context,
         private val falsingManager: FalsingManager,
         private val footerActionsInteractor: FooterActionsInteractor,
         private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>,
@@ -175,7 +176,7 @@
 }
 
 fun FooterActionsViewModel(
-    @Application appContext: Context,
+    @ShadeDisplayAware appContext: Context,
     footerActionsInteractor: FooterActionsInteractor,
     falsingManager: FalsingManager,
     globalActionsDialogLite: GlobalActionsDialogLite,
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 0e09ad2..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
@@ -228,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/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
index 4e34e73..faab696 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
@@ -56,7 +56,7 @@
     private val tilesAvailabilityInteractor: TilesAvailabilityInteractor,
     private val minTilesInteractor: MinimumTilesInteractor,
     @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor,
-    @Application private val applicationContext: Context,
+    @ShadeDisplayAware  private val context: Context,
     @Named("Default") private val defaultGridLayout: GridLayout,
     @Application private val applicationScope: CoroutineScope,
     gridLayoutTypeInteractor: GridLayoutTypeInteractor,
@@ -140,7 +140,7 @@
                     .combine(configurationInteractor.onAnyConfigurationChange.emitOnStart()) {
                         tiles,
                         _ ->
-                        tiles.fastMap { it.load(applicationContext) }
+                        tiles.fastMap { it.load(context) }
                     }
             } else {
                 emptyFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
index c5b2737..41cdefd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt
@@ -30,8 +30,8 @@
 import com.android.systemui.common.data.repository.PackageChangeRepository
 import com.android.systemui.common.shared.model.PackageChangeModel
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.kotlin.isComponentActuallyEnabled
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -54,7 +54,7 @@
 class InstalledTilesComponentRepositoryImpl
 @Inject
 constructor(
-    @Application private val applicationContext: Context,
+    @ShadeDisplayAware private val context: Context,
     @Background private val backgroundScope: CoroutineScope,
     private val packageChangeRepository: PackageChangeRepository
 ) : InstalledTilesComponentRepository {
@@ -77,10 +77,10 @@
              * context.
              */
             val packageManager =
-                if (applicationContext.userId == userId) {
-                    applicationContext.packageManager
+                if (context.userId == userId) {
+                    context.packageManager
                 } else {
-                    applicationContext
+                    context
                         .createContextAsUser(
                             UserHandle.of(userId),
                             /* flags */ 0,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
index 31ea734..e9c91ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.qs.pipeline.domain.model.AutoAddable
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
@@ -42,7 +43,7 @@
 @Inject
 constructor(
     private val nightDisplayListenerBuilder: NightDisplayListenerModule.Builder,
-    context: Context,
+    @ShadeDisplayAware context: Context,
 ) : AutoAddable {
 
     private val enabled = ColorDisplayManager.isNightDisplayAvailable(context)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 6b654be..fed8b60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -39,6 +39,7 @@
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.qs.user.UserSwitchDialogController;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -95,7 +96,7 @@
         }
 
         @Inject
-        public Adapter(Context context, UserSwitcherController controller,
+        public Adapter(@ShadeDisplayAware Context context, UserSwitcherController controller,
                 UiEventLogger uiEventLogger, FalsingManager falsingManager) {
             super(controller);
             mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
index 87b89ea..4577527 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractor.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor.PolicyResult
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
@@ -70,7 +71,7 @@
 class DisabledByPolicyInteractorImpl
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val activityStarter: ActivityStarter,
     private val restrictedLockProxy: RestrictedLockProxy,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
@@ -105,7 +106,7 @@
 
 /** Mockable proxy for [RestrictedLockUtilsInternal] static methods. */
 @VisibleForTesting
-class RestrictedLockProxy @Inject constructor(private val context: Context) {
+class RestrictedLockProxy @Inject constructor(@ShadeDisplayAware private val context: Context) {
 
     @WorkerThread
     fun hasBaseUserRestriction(userId: Int, userRestriction: String?): Boolean =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
index b766ee0..222fa3e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/QSTilesModule.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProviderImpl
 import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.shade.ShadeDisplayAware
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
@@ -66,6 +67,6 @@
 
     companion object {
 
-        @Provides fun provideTilesTheme(context: Context): Theme = context.theme
+        @Provides fun provideTilesTheme(@ShadeDisplayAware context: Context): Theme = context.theme
     }
 }
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 8f6c4e7..244f024 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
@@ -87,6 +87,7 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.statusbar.connectivity.AccessPointController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -240,7 +241,7 @@
     }
 
     @Inject
-    public InternetDialogController(@NonNull Context context, UiEventLogger uiEventLogger,
+    public InternetDialogController(@ShadeDisplayAware Context context, UiEventLogger uiEventLogger,
             ActivityStarter starter, AccessPointController accessPointController,
             SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
             @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index 89b9eee..0ab533b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -71,6 +71,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.ShadeDisplayAware;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.wifitrackerlib.WifiEntry;
@@ -190,7 +191,7 @@
 
     @AssistedInject
     public InternetDialogDelegate(
-            Context context,
+            @ShadeDisplayAware Context context,
             InternetDialogManager internetDialogManager,
             InternetDialogController internetDialogController,
             @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
index 1546ec2..32fb1d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileDefaultsRepository.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults
 import com.android.systemui.qs.tiles.impl.di.QSTileScope
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -68,7 +69,7 @@
 class CustomTileDefaultsRepositoryImpl
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @Application applicationScope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : CustomTileDefaultsRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
index 0ebd6f2..cd4938f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTilePackageUpdatesRepository.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.tiles.impl.di.QSTileScope
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
@@ -51,7 +52,7 @@
 @Inject
 constructor(
     private val tileSpec: TileSpec.CustomTileSpec,
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @QSTileScope private val tileScope: CoroutineScope,
     @Background private val backgroundCoroutineContext: CoroutineContext,
 ) : CustomTilePackageUpdatesRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
index 60aa4ea..c446865 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/CustomTileMapper.kt
@@ -30,12 +30,16 @@
 import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
 import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 
 @SysUISingleton
 class CustomTileMapper
 @Inject
-constructor(private val context: Context, private val uriGrantsManager: IUriGrantsManager) :
+constructor(
+    @ShadeDisplayAware private val context: Context,
+    private val uriGrantsManager: IUriGrantsManager
+) :
     QSTileDataToStateMapper<CustomTileDataModel> {
 
     override fun map(config: QSTileConfig, data: CustomTileDataModel): QSTileState {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
index af2bb9d..1153b5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.qs.tiles.impl.di.QSTileScope
 import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
 import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shade.ShadeDisplayAware
 import java.util.concurrent.atomic.AtomicReference
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
@@ -51,7 +52,7 @@
 class CustomTileUserActionInteractor
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val tileSpec: TileSpec,
     private val qsTileLogger: QSTileLogger,
     private val windowManager: IWindowManager,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
index fc94585..1a6876d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
 import com.android.systemui.qs.tiles.viewmodel.QSTileState
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileIconModel
 import javax.inject.Inject
 
@@ -37,9 +38,9 @@
 class InternetTileMapper
 @Inject
 constructor(
-    @Main private val resources: Resources,
+    @ShadeDisplayAware private val resources: Resources,
     private val theme: Resources.Theme,
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @Main private val handler: Handler,
 ) : QSTileDataToStateMapper<InternetTileModel> {
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
index 6fe3979..6d10843 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractor.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
 import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
 import com.android.systemui.res.R
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -54,7 +55,7 @@
 class InternetTileDataInteractor
 @Inject
 constructor(
-    private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @Application private val scope: CoroutineScope,
     airplaneModeRepository: AirplaneModeRepository,
     private val connectivityRepository: ConnectivityRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 3e442582..9b2880b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
 import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
 import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo
@@ -42,7 +43,7 @@
 class ModesTileDataInteractor
 @Inject
 constructor(
-    val context: Context,
+    @ShadeDisplayAware val context: Context,
     val zenModeInteractor: ZenModeInteractor,
     @Background val bgDispatcher: CoroutineDispatcher,
 ) : QSTileDataInteractor<ModesTileModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
index 252e3f8..05bdf0a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.qs.tiles.impl.saver.domain.model.DataSaverTileModel
 import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
 import com.android.systemui.settings.UserFileManager
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.DataSaverController
 import javax.inject.Inject
@@ -42,7 +43,7 @@
 class DataSaverTileUserActionInteractor
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     @Main private val coroutineContext: CoroutineContext,
     @Background private val backgroundContext: CoroutineContext,
     private val dataSaverController: DataSaverController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
index c928e8a..7af3576 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
 import com.android.systemui.qs.tiles.impl.uimodenight.domain.model.UiModeNightTileModel
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.LocationController
@@ -38,7 +39,7 @@
 class UiModeNightTileDataInteractor
 @Inject
 constructor(
-    @Application private val context: Context,
+    @ShadeDisplayAware private val context: Context,
     private val configurationController: ConfigurationController,
     private val uiModeManager: UiModeManager,
     private val batteryController: BatteryController,
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt
new file mode 100644
index 0000000..bc15bbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.reardisplay
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager
+import android.hardware.devicestate.feature.flags.Flags
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+
+/**
+ * Provides a {@link com.android.systemui.statusbar.phone.SystemUIDialog} to be shown on the inner
+ * display when the device enters Rear Display Mode, containing an UI affordance to let the user
+ * know that the main content has moved to the outer display, as well as an UI affordance to cancel
+ * the Rear Display Mode.
+ */
+@SysUISingleton
+class RearDisplayCoreStartable
+@Inject
+internal constructor(
+    private val context: Context,
+    private val deviceStateManager: DeviceStateManager,
+    private val rearDisplayStateInteractor: RearDisplayStateInteractor,
+    private val rearDisplayInnerDialogDelegateFactory: RearDisplayInnerDialogDelegate.Factory,
+    @Application private val scope: CoroutineScope,
+) : CoreStartable, AutoCloseable {
+
+    companion object {
+        private const val TAG: String = "RearDisplayCoreStartable"
+    }
+
+    @VisibleForTesting var stateChangeListener: Job? = null
+
+    override fun close() {
+        stateChangeListener?.cancel()
+    }
+
+    override fun start() {
+        if (Flags.deviceStateRdmV2()) {
+            var dialog: SystemUIDialog? = null
+
+            stateChangeListener =
+                rearDisplayStateInteractor.state
+                    .map {
+                        when (it) {
+                            is RearDisplayStateInteractor.State.Enabled -> {
+                                val rearDisplayContext =
+                                    context.createDisplayContext(it.innerDisplay)
+                                val delegate =
+                                    rearDisplayInnerDialogDelegateFactory.create(
+                                        rearDisplayContext,
+                                        deviceStateManager::cancelStateRequest,
+                                    )
+                                dialog = delegate.createDialog().apply { show() }
+                            }
+
+                            is RearDisplayStateInteractor.State.Disabled -> {
+                                dialog?.dismiss()
+                                dialog = null
+                            }
+                        }
+                    }
+                    .launchIn(scope)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt
new file mode 100644
index 0000000..2d6181a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.reardisplay
+
+import android.content.Context
+import android.os.Bundle
+import android.view.View
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * A {@link com.android.systemui.statusbar.phone.SystemUIDialog.Delegate} providing a dialog which
+ * lets the user know that the Rear Display Mode is active, and that the content has moved to the
+ * outer display.
+ */
+class RearDisplayInnerDialogDelegate
+@AssistedInject
+internal constructor(
+    private val systemUIDialogFactory: SystemUIDialog.Factory,
+    @Assisted private val rearDisplayContext: Context,
+    @Assisted private val onCanceledRunnable: Runnable,
+) : SystemUIDialog.Delegate {
+
+    @AssistedFactory
+    interface Factory {
+        fun create(
+            rearDisplayContext: Context,
+            onCanceledRunnable: Runnable,
+        ): RearDisplayInnerDialogDelegate
+    }
+
+    override fun createDialog(): SystemUIDialog {
+        return systemUIDialogFactory.create(this, rearDisplayContext)
+    }
+
+    override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+        dialog.apply {
+            setContentView(R.layout.activity_rear_display_front_screen_on)
+            setCanceledOnTouchOutside(false)
+            requireViewById<View>(R.id.button_cancel).setOnClickListener {
+                onCanceledRunnable.run()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
index 6ab294d..5fb9cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt
@@ -41,4 +41,10 @@
     fun bindRearDisplayDialogControllerConfigChanges(
         impl: RearDisplayDialogController
     ): ConfigurationListener
+
+    /** Start RearDisplayCoreStartable. */
+    @Binds
+    @IntoMap
+    @ClassKey(RearDisplayCoreStartable::class)
+    abstract fun bindRearDisplayCoreStartable(impl: RearDisplayCoreStartable): CoreStartable
 }
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 9dc2cba..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,6 +37,9 @@
     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.
@@ -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 0e82bf8..4ccd2b9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -3109,12 +3109,18 @@
         if (isTracking()) {
             onTrackingStopped(true);
         }
-        if (isExpanded() && !mQsController.getExpanded()) {
+        if (isExpanded() && mBarState != KEYGUARD && !mQsController.getExpanded()) {
             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();
+            }
         }
     }
 
@@ -5091,13 +5097,6 @@
             }
             boolean handled = mHeadsUpTouchHelper.onTouchEvent(event);
 
-            if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch(
-                    event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) {
-                if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
-                    mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
-                }
-                return true;
-            }
             // This touch session has already resulted in shade expansion. Ignore everything else.
             if (ShadeExpandsOnStatusBarLongPress.isEnabled()
                     && event.getActionMasked() != MotionEvent.ACTION_DOWN
@@ -5105,6 +5104,13 @@
                 mShadeLog.d("Touch has same down time as Status Bar long press. Ignoring.");
                 return false;
             }
+            if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch(
+                    event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) {
+                if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+                    mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
+                }
+                return true;
+            }
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
                 mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
                 handled = true;
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/LongPressGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt
rename to packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
index 6fb3ca5..ae36e81 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
@@ -25,7 +25,7 @@
 
 /** Accepts touch events, detects long press, and calls ShadeViewController#onStatusBarLongPress. */
 @SysUISingleton
-class LongPressGestureDetector
+class StatusBarLongPressGestureDetector
 @Inject
 constructor(context: Context, val shadeViewController: ShadeViewController) {
     val gestureDetector =
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
index 4e7898d..1055dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -30,7 +30,7 @@
 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.ShadePositionRepository
+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
@@ -38,13 +38,13 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.withContext
 
-/** Handles Shade window display change when [ShadePositionRepository.displayId] changes. */
+/** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */
 @SysUISingleton
 class ShadeDisplaysInteractor
 @Inject
 constructor(
     private val shadeRootView: WindowRootView,
-    private val shadePositionRepository: ShadePositionRepository,
+    private val shadePositionRepository: ShadeDisplaysRepository,
     @ShadeDisplayAware private val shadeContext: Context,
     private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
     @Background private val bgScope: CoroutineScope,
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/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/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 684ce48..42aadd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -76,6 +76,7 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
+import com.android.systemui.statusbar.notification.logging.dagger.NotificationsLogModule;
 import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory;
 import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -116,6 +117,7 @@
         ActivatableNotificationViewModelModule.class,
         NotificationMemoryModule.class,
         NotificationStatsLoggerModule.class,
+        NotificationsLogModule.class,
 })
 public interface NotificationsModule {
     @Binds
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/logging/dagger/NotificationsLogModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt
new file mode 100644
index 0000000..d3359d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt
@@ -0,0 +1,152 @@
+/*
+ * 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.logging.dagger
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.log.dagger.NotifInteractionLog
+import com.android.systemui.log.dagger.NotificationHeadsUpLog
+import com.android.systemui.log.dagger.NotificationInterruptLog
+import com.android.systemui.log.dagger.NotificationLockscreenLog
+import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.log.dagger.NotificationRemoteInputLog
+import com.android.systemui.log.dagger.NotificationRenderLog
+import com.android.systemui.log.dagger.NotificationSectionLog
+import com.android.systemui.log.dagger.SensitiveNotificationProtectionLog
+import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.log.dagger.VisualStabilityLog
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLog
+import com.android.systemui.util.Compile
+import dagger.Module
+import dagger.Provides
+
+@Module
+object NotificationsLogModule {
+    /** Provides a logging buffer for logs related to heads up presentation of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotificationHeadsUpLog
+    fun provideNotificationHeadsUpLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifHeadsUpLog", 1000)
+    }
+
+    /** Provides a logging buffer for logs related to inflation of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotifInflationLog
+    fun provideNotifInflationLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifInflationLog", 250)
+    }
+
+    /** Provides a logging buffer for all logs related to the data layer of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotifInteractionLog
+    fun provideNotifInteractionLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifInteractionLog", 50)
+    }
+
+    /** Provides a logging buffer for notification interruption calculations. */
+    @Provides
+    @SysUISingleton
+    @NotificationInterruptLog
+    fun provideNotificationInterruptLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifInterruptLog", 100)
+    }
+
+    /** Provides a logging buffer for all logs related to notifications on the lockscreen. */
+    @Provides
+    @SysUISingleton
+    @NotificationLockscreenLog
+    fun provideNotificationLockScreenLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifLockscreenLog", 50, false /* systrace */)
+    }
+
+    /** Provides a logging buffer for all logs related to the data layer of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotificationLog
+    fun provideNotificationsLogBuffer(
+        factory: LogBufferFactory,
+        notifPipelineFlags: NotifPipelineFlags,
+    ): LogBuffer {
+        var maxSize = 1000
+        if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) {
+            maxSize *= 10
+        }
+        return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */)
+    }
+
+    /** Provides a logging buffer for all logs related to remote input controller. */
+    @Provides
+    @SysUISingleton
+    @NotificationRemoteInputLog
+    fun provideNotificationRemoteInputLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifRemoteInputLog", 50, /* maxSize */ false /* systrace */)
+    }
+
+    /** Provides a logging buffer for notification rendering events. */
+    @Provides
+    @SysUISingleton
+    @NotificationRenderLog
+    fun provideNotificationRenderLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifRenderLog", 100)
+    }
+
+    /** Provides a logging buffer for all logs related to managing notification sections. */
+    @Provides
+    @SysUISingleton
+    @NotificationSectionLog
+    fun provideNotificationSectionLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("NotifSectionLog", 1000, /* maxSize */ false /* systrace */)
+    }
+
+    /** Provides a [LogBuffer] for use by promoted notifications. */
+    @Provides
+    @SysUISingleton
+    @PromotedNotificationLog
+    fun providesPromotedNotificationLog(factory: LogBufferFactory): LogBuffer {
+        return factory.create("PromotedNotifLog", 50)
+    }
+
+    /**  */
+    @Provides
+    @SysUISingleton
+    @SensitiveNotificationProtectionLog
+    fun provideSensitiveNotificationProtectionLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("SensitiveNotificationProtectionLog", 10)
+    }
+
+    /** Provides a logging buffer for all logs related to unseen notifications. */
+    @Provides
+    @SysUISingleton
+    @UnseenNotificationLog
+    fun provideUnseenNotificationLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("UnseenNotifLog", 20, /* maxSize */ false /* systrace */)
+    }
+
+    /** Provides a logging buffer for all logs related to notification visual stability. */
+    @Provides
+    @SysUISingleton
+    @VisualStabilityLog
+    fun provideVisualStabilityLogBuffer(factory: LogBufferFactory): LogBuffer {
+        return factory.create("VisualStabilityLog", 50, /* maxSize */ false /* systrace */)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt
new file mode 100644
index 0000000..f9d9c97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.promoted
+
+import javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for use by promoted notifications. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class PromotedNotificationLog
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/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
index 0738a03..1ff0d92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Flags;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.drawable.Icon;
@@ -93,12 +94,22 @@
         }
         mConversationSenderName = requireViewById(R.id.conversation_notification_sender);
         applyTextColor(mConversationSenderName, mSecondaryTextColor);
-        mFacePileSize = getResources()
-                .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
-        mFacePileAvatarSize = getResources()
-                .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
-        mSingleAvatarSize = getResources()
-                .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
+        if (Flags.notificationsRedesignTemplates()) {
+            mFacePileSize = getResources()
+                    .getDimensionPixelSize(R.dimen.notification_2025_single_line_face_pile_size);
+            mFacePileAvatarSize = getResources()
+                    .getDimensionPixelSize(
+                            R.dimen.notification_2025_single_line_face_pile_avatar_size);
+            mSingleAvatarSize = getResources()
+                    .getDimensionPixelSize(R.dimen.notification_2025_single_line_avatar_size);
+        } else {
+            mFacePileSize = getResources()
+                    .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
+            mFacePileAvatarSize = getResources()
+                    .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
+            mSingleAvatarSize = getResources()
+                    .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
+        }
         mFacePileProtectionWidth = getResources().getDimensionPixelSize(
                 R.dimen.conversation_single_line_face_pile_protection_width);
         mTransformationHelper.setCustomTransformation(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 09c0349..e5e559f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -63,9 +63,8 @@
     private HybridNotificationView inflateHybridView(View contentView, ViewGroup parent) {
         Trace.beginSection("HybridGroupManager#inflateHybridView");
         LayoutInflater inflater = LayoutInflater.from(mContext);
-        int layout = contentView instanceof ConversationLayout
-                ? R.layout.hybrid_conversation_notification
-                : R.layout.hybrid_notification;
+        int layout = HybridNotificationView.getLayoutResource(
+                /* isConversation = */ contentView instanceof ConversationLayout);
         HybridNotificationView hybrid = (HybridNotificationView)
                 inflater.inflate(layout, parent, false);
         parent.addView(hybrid);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
index da8c4dc..61f4e96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
@@ -19,6 +19,7 @@
 import static android.app.Notification.COLOR_INVALID;
 
 import android.annotation.Nullable;
+import android.app.Flags;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.text.TextUtils;
@@ -73,6 +74,25 @@
         return mTextView;
     }
 
+    /**
+     * Get layout resource for this view based on {@param isConversation}.
+     */
+    public static int getLayoutResource(boolean isConversation) {
+        if (Flags.notificationsRedesignTemplates()) {
+            if (isConversation) {
+                return R.layout.notification_2025_hybrid_conversation;
+            } else {
+                return R.layout.notification_2025_hybrid;
+            }
+        } else {
+            if (isConversation) {
+                return R.layout.hybrid_conversation_notification;
+            } else {
+                return R.layout.hybrid_notification;
+            }
+        }
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
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/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 2dcb706..d0c033b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -834,6 +834,15 @@
             public?.let {
                 it.layoutInflaterFactory = provider.provide(row, FLAG_CONTENT_VIEW_PUBLIC)
             }
+            if (android.app.Flags.notificationsRedesignAppIcons()) {
+                normalGroupHeader?.let {
+                    it.layoutInflaterFactory = provider.provide(row, FLAG_GROUP_SUMMARY_HEADER)
+                }
+                minimizedGroupHeader?.let {
+                    it.layoutInflaterFactory =
+                        provider.provide(row, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)
+                }
+            }
             return this
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index 4e26ae8..e702f10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -412,10 +412,7 @@
 
         traceSection("SingleLineViewInflater#inflateSingleLineView") {
             val inflater = LayoutInflater.from(context)
-            val layoutRes: Int =
-                if (isConversation)
-                    com.android.systemui.res.R.layout.hybrid_conversation_notification
-                else com.android.systemui.res.R.layout.hybrid_notification
+            val layoutRes: Int = HybridNotificationView.getLayoutResource(isConversation)
             view = inflater.inflate(layoutRes, /* root= */ null) as HybridNotificationView
             if (view == null) {
                 Log.wtf(TAG, "Single-line view inflation result is null for entry: ${entry.logKey}")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index db29493..80c8e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -171,12 +171,14 @@
 import com.android.systemui.shade.NotificationShadeWindowViewController;
 import com.android.systemui.shade.QuickSettingsController;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.shade.ShadeExpansionListener;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.shade.ShadeLogger;
 import com.android.systemui.shade.ShadeSurface;
 import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.statusbar.phone.BarTransitions;
 import com.android.systemui.statusbar.AutoHideUiElement;
@@ -366,6 +368,7 @@
 
     private PhoneStatusBarViewController mPhoneStatusBarViewController;
     private PhoneStatusBarTransitions mStatusBarTransitions;
+    private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector;
     private final AuthRippleController mAuthRippleController;
     @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
@@ -671,6 +674,7 @@
             ShadeController shadeController,
             WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector,
             ViewMediatorCallback viewMediatorCallback,
             InitController initController,
             @Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler,
@@ -778,6 +782,7 @@
         mShadeController = shadeController;
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
         mKeyguardViewMediatorCallback = viewMediatorCallback;
         mInitController = initController;
         mPluginDependencyProvider = pluginDependencyProvider;
@@ -1527,6 +1532,11 @@
                 // to touch outside the customizer to close it, such as on the status or nav bar.
                 mShadeController.onStatusBarTouch(event);
             }
+            if (ShadeExpandsOnStatusBarLongPress.isEnabled()
+                    && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                mStatusBarLongPressGestureDetector.get().handleTouch(event);
+            }
+
             return getNotificationShadeWindowView().onTouchEvent(event);
         };
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index 7ef1e41..5837a49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -31,6 +31,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -63,17 +64,21 @@
 
     @Override
     public void addCallback(@NonNull Callback callback) {
-        mCallbacks.add(callback);
-        if (mCallbacks.size() == 1) {
-            setListening(true);
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
+            if (mCallbacks.size() == 1) {
+                setListening(true);
+            }
+            callback.onManagedProfileChanged();
         }
-        callback.onManagedProfileChanged();
     }
 
     @Override
     public void removeCallback(@NonNull Callback callback) {
-        if (mCallbacks.remove(callback) && mCallbacks.size() == 0) {
-            setListening(false);
+        synchronized (mCallbacks) {
+            if (mCallbacks.remove(callback) && mCallbacks.size() == 0) {
+                setListening(false);
+            }
         }
     }
 
@@ -109,10 +114,7 @@
     }
 
     private void notifyManagedProfileRemoved() {
-        ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
-        for (Callback callback : copy) {
-            callback.onManagedProfileRemoved();
-        }
+        notifyCallbacks(Callback::onManagedProfileRemoved);
     }
 
     public boolean hasActiveProfile() {
@@ -136,6 +138,16 @@
         }
     }
 
+    private void notifyCallbacks(Consumer<Callback> method) {
+        ArrayList<Callback> copy;
+        synchronized (mCallbacks) {
+            copy = new ArrayList<>(mCallbacks);
+        }
+        for (Callback callback : copy) {
+            method.accept(callback);
+        }
+    }
+
     private void setListening(boolean listening) {
         if (mListening == listening) {
             return;
@@ -154,19 +166,13 @@
         @Override
         public void onUserChanged(int newUser, @NonNull Context userContext) {
             reloadManagedProfiles();
-            ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
-            for (Callback callback : copy) {
-                callback.onManagedProfileChanged();
-            }
+            notifyCallbacks(Callback::onManagedProfileChanged);
         }
 
         @Override
         public void onProfilesChanged(@NonNull List<UserInfo> profiles) {
             reloadManagedProfiles();
-            ArrayList<Callback> copy = new ArrayList<>(mCallbacks);
-            for (Callback callback : copy) {
-                callback.onManagedProfileChanged();
-            }
+            notifyCallbacks(Callback::onManagedProfileChanged);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 91c43dd..176dd8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -39,8 +39,8 @@
 import com.android.systemui.Flags;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.res.R;
-import com.android.systemui.shade.LongPressGestureDetector;
 import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
@@ -69,7 +69,7 @@
     private InsetsFetcher mInsetsFetcher;
     private int mDensity;
     private float mFontScale;
-    private LongPressGestureDetector mLongPressGestureDetector;
+    private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
 
     /**
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
@@ -81,9 +81,10 @@
         mStatusBarWindowControllerStore = Dependency.get(StatusBarWindowControllerStore.class);
     }
 
-    void setLongPressGestureDetector(LongPressGestureDetector longPressGestureDetector) {
+    void setLongPressGestureDetector(
+            StatusBarLongPressGestureDetector statusBarLongPressGestureDetector) {
         if (ShadeExpandsOnStatusBarLongPress.isEnabled()) {
-            mLongPressGestureDetector = longPressGestureDetector;
+            mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
         }
     }
 
@@ -207,8 +208,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (ShadeExpandsOnStatusBarLongPress.isEnabled() && mLongPressGestureDetector != null) {
-            mLongPressGestureDetector.handleTouch(event);
+        if (ShadeExpandsOnStatusBarLongPress.isEnabled()
+                && mStatusBarLongPressGestureDetector != null) {
+            mStatusBarLongPressGestureDetector.handleTouch(event);
         }
         if (mTouchEventHandler == null) {
             Log.w(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index a94db49..16e023c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -34,11 +34,11 @@
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.ui.view.WindowRootView
-import com.android.systemui.shade.LongPressGestureDetector
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress
 import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.StatusBarLongPressGestureDetector
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore
@@ -69,7 +69,7 @@
     private val shadeController: ShadeController,
     private val shadeViewController: ShadeViewController,
     private val panelExpansionInteractor: PanelExpansionInteractor,
-    private val longPressGestureDetector: Provider<LongPressGestureDetector>,
+    private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>,
     private val windowRootView: Provider<WindowRootView>,
     private val shadeLogger: ShadeLogger,
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
@@ -119,7 +119,7 @@
         addCursorSupportToIconContainers()
 
         if (ShadeExpandsOnStatusBarLongPress.isEnabled) {
-            mView.setLongPressGestureDetector(longPressGestureDetector.get())
+            mView.setLongPressGestureDetector(statusBarLongPressGestureDetector.get())
         }
 
         progressProvider?.setReadyToHandleTransition(true)
@@ -336,7 +336,7 @@
         private val shadeController: ShadeController,
         private val shadeViewController: ShadeViewController,
         private val panelExpansionInteractor: PanelExpansionInteractor,
-        private val longPressGestureDetector: Provider<LongPressGestureDetector>,
+        private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>,
         private val windowRootView: Provider<WindowRootView>,
         private val shadeLogger: ShadeLogger,
         private val viewUtil: ViewUtil,
@@ -361,7 +361,7 @@
                 shadeController,
                 shadeViewController,
                 panelExpansionInteractor,
-                longPressGestureDetector,
+                statusBarLongPressGestureDetector,
                 windowRootView,
                 shadeLogger,
                 statusBarMoveFromCenterAnimationController,
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 a1b56d6..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)
         }
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/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index d371acf..66a900b 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -18,6 +18,7 @@
 
 import android.content.res.Configuration
 import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
@@ -36,8 +37,12 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.input.pointer.pointerInteropFilter
@@ -49,6 +54,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.touchpad.tutorial.ui.gesture.isFourFingerTouchpadSwipe
 import com.android.systemui.touchpad.tutorial.ui.gesture.isThreeFingerTouchpadSwipe
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen
 
 @Composable
 fun TutorialSelectionScreen(
@@ -56,6 +62,7 @@
     onHomeTutorialClicked: () -> Unit,
     onRecentAppsTutorialClicked: () -> Unit,
     onDoneButtonClicked: () -> Unit,
+    lastSelectedScreen: Screen,
 ) {
     Column(
         verticalArrangement = Arrangement.Center,
@@ -80,6 +87,7 @@
                     onHomeTutorialClicked = onHomeTutorialClicked,
                     onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
                     modifier = Modifier.weight(1f).padding(60.dp),
+                    lastSelectedScreen,
                 )
             }
             else -> {
@@ -88,6 +96,7 @@
                     onHomeTutorialClicked = onHomeTutorialClicked,
                     onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
                     modifier = Modifier.weight(1f).padding(60.dp),
+                    lastSelectedScreen,
                 )
             }
         }
@@ -105,6 +114,7 @@
     onHomeTutorialClicked: () -> Unit,
     onRecentAppsTutorialClicked: () -> Unit,
     modifier: Modifier = Modifier,
+    lastSelectedScreen: Screen,
 ) {
     Row(
         horizontalArrangement = Arrangement.spacedBy(20.dp),
@@ -116,6 +126,7 @@
             onHomeTutorialClicked,
             onRecentAppsTutorialClicked,
             modifier = Modifier.weight(1f).fillMaxSize(),
+            lastSelectedScreen,
         )
     }
 }
@@ -126,6 +137,7 @@
     onHomeTutorialClicked: () -> Unit,
     onRecentAppsTutorialClicked: () -> Unit,
     modifier: Modifier = Modifier,
+    lastSelectedScreen: Screen,
 ) {
     Column(
         verticalArrangement = Arrangement.spacedBy(20.dp),
@@ -137,6 +149,7 @@
             onHomeTutorialClicked,
             onRecentAppsTutorialClicked,
             modifier = Modifier.weight(1f).fillMaxSize(),
+            lastSelectedScreen,
         )
     }
 }
@@ -147,14 +160,26 @@
     onHomeTutorialClicked: () -> Unit,
     onRecentAppsTutorialClicked: () -> Unit,
     modifier: Modifier = Modifier,
+    lastSelectedScreen: Screen,
 ) {
+    val homeFocusRequester = remember { FocusRequester() }
+    val backFocusRequester = remember { FocusRequester() }
+    val recentAppsFocusRequester = remember { FocusRequester() }
+    LaunchedEffect(Unit) {
+        when (lastSelectedScreen) {
+            Screen.HOME_GESTURE -> homeFocusRequester.requestFocus()
+            Screen.BACK_GESTURE -> backFocusRequester.requestFocus()
+            Screen.RECENT_APPS_GESTURE -> recentAppsFocusRequester.requestFocus()
+            else -> {} // No-Op.
+        }
+    }
     TutorialButton(
         text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
         icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon),
         iconColor = MaterialTheme.colorScheme.onPrimary,
         onClick = onHomeTutorialClicked,
         backgroundColor = MaterialTheme.colorScheme.primary,
-        modifier = modifier,
+        modifier = modifier.focusRequester(homeFocusRequester).focusable(),
     )
     TutorialButton(
         text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
@@ -162,7 +187,7 @@
         iconColor = MaterialTheme.colorScheme.onTertiary,
         onClick = onBackTutorialClicked,
         backgroundColor = MaterialTheme.colorScheme.tertiary,
-        modifier = modifier,
+        modifier = modifier.focusRequester(backFocusRequester).focusable(),
     )
     TutorialButton(
         text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
@@ -170,7 +195,7 @@
         iconColor = MaterialTheme.colorScheme.onSecondary,
         onClick = onRecentAppsTutorialClicked,
         backgroundColor = MaterialTheme.colorScheme.secondary,
-        modifier = modifier,
+        modifier = modifier.focusRequester(recentAppsFocusRequester).focusable(),
     )
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index e1f7bd5..6662fc5 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -24,12 +24,16 @@
 import androidx.activity.viewModels
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
 import androidx.lifecycle.Lifecycle.State.STARTED
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.theme.PlatformTheme
 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
 import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
 import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialMetricsLogger
+import com.android.systemui.res.R
 import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
 import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
 import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
@@ -54,6 +58,7 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         enableEdgeToEdge()
+        setTitle(getString(R.string.launch_touchpad_tutorial_notification_content))
         setContent {
             PlatformTheme { TouchpadTutorialScreen(vm, closeTutorial = ::finishTutorial) }
         }
@@ -82,13 +87,24 @@
 @Composable
 fun TouchpadTutorialScreen(vm: TouchpadTutorialViewModel, closeTutorial: () -> Unit) {
     val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
+    var lastSelectedScreen by remember { mutableStateOf(TUTORIAL_SELECTION) }
     when (activeScreen) {
         TUTORIAL_SELECTION ->
             TutorialSelectionScreen(
-                onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
-                onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
-                onRecentAppsTutorialClicked = { vm.goTo(RECENT_APPS_GESTURE) },
+                onBackTutorialClicked = {
+                    lastSelectedScreen = BACK_GESTURE
+                    vm.goTo(BACK_GESTURE)
+                },
+                onHomeTutorialClicked = {
+                    lastSelectedScreen = HOME_GESTURE
+                    vm.goTo(HOME_GESTURE)
+                },
+                onRecentAppsTutorialClicked = {
+                    lastSelectedScreen = RECENT_APPS_GESTURE
+                    vm.goTo(RECENT_APPS_GESTURE)
+                },
                 onDoneButtonClicked = closeTutorial,
+                lastSelectedScreen,
             )
         BACK_GESTURE ->
             BackGestureTutorialScreen(
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 63a5b3f..fb09ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -28,6 +28,7 @@
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
+import kotlin.coroutines.cancellation.CancellationException
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DisposableHandle
 import kotlinx.coroutines.Job
@@ -64,6 +65,28 @@
     ): StateFlow<T> {
         return flow.stateIn(scope, started, initialValue)
     }
+
+    /** Call suspend functions from Java */
+    fun <T, R> callSuspend(
+        suspendFunction: suspend (T) -> R,
+        arg: T,
+        onSuccess: (R) -> Unit,
+        onCancel: (CancellationException) -> Unit,
+        onFailure: (Throwable) -> Unit,
+    ): Job =
+        scope.launch {
+            val result =
+                try {
+                    suspendFunction(arg)
+                } catch (ex: CancellationException) {
+                    onCancel(ex)
+                    return@launch
+                } catch (ex: Throwable) {
+                    onFailure(ex)
+                    return@launch
+                }
+            onSuccess(result)
+        }
 }
 
 /**
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 2a9b1b9..e5c1e7d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -17,14 +17,16 @@
 package com.android.systemui.util.kotlin
 
 import android.os.Handler
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 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 java.util.concurrent.Executor
+import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DelicateCoroutinesApi
@@ -33,8 +35,6 @@
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.newFixedThreadPoolContext
 import kotlinx.coroutines.plus
-import java.util.concurrent.Executor
-import kotlin.coroutines.CoroutineContext
 
 private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true
 
@@ -62,7 +62,7 @@
     @Background
     @Deprecated(
         "Use @Background CoroutineContext instead",
-        ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+        ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
     )
     fun bgDispatcher(): CoroutineDispatcher {
         return if (LIMIT_BACKGROUND_DISPATCHER_THREADS) {
@@ -73,7 +73,7 @@
             // code on those.
             newFixedThreadPoolContext(
                 nThreads = Runtime.getRuntime().availableProcessors(),
-                name = "SystemUIBg"
+                name = "SystemUIBg",
             )
         } else {
             Dispatchers.IO
@@ -89,10 +89,17 @@
     }
 
     @Provides
+    @SysUISingleton
+    @SettingsSingleThreadBackground
+    fun settingsScope(@Background bgDispatcher: CoroutineDispatcher): CoroutineScope {
+        return CoroutineScope(bgDispatcher + newTracingContext("SettingsProxy"))
+    }
+
+    @Provides
     @Background
     @SysUISingleton
     fun bgCoroutineContext(
-        @Background bgCoroutineDispatcher: CoroutineDispatcher,
+        @Background bgCoroutineDispatcher: CoroutineDispatcher
     ): CoroutineContext {
         return bgCoroutineDispatcher
     }
@@ -103,7 +110,7 @@
     @UiBackground
     @Deprecated(
         "Use @UiBackground CoroutineContext instead",
-        ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+        ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
     )
     fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher =
         uiBgExecutor.asCoroutineDispatcher()
@@ -112,7 +119,7 @@
     @UiBackground
     @SysUISingleton
     fun uiBgCoroutineContext(
-        @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher,
+        @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher
     ): CoroutineContext {
         return uiBgCoroutineDispatcher
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index b705872..68bffeef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -18,8 +18,6 @@
 
 import static android.media.AudioManager.RINGER_MODE_NORMAL;
 
-import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
-
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.NotificationManager;
@@ -79,9 +77,13 @@
 import com.android.systemui.util.concurrency.ThreadFactory;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
 
 import dalvik.annotation.optimization.NeverCompile;
 
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.Map;
@@ -155,6 +157,7 @@
     private final VibratorHelper mVibrator;
     private final AudioSharingInteractor mAudioSharingInteractor;
     private final JavaAdapter mJavaAdapter;
+    private final VolumeLogger mVolumeLogger;
     private final boolean mHasVibrator;
     private boolean mShowA11yStream;
     private boolean mShowVolumeDialog;
@@ -202,7 +205,8 @@
             UserTracker userTracker,
             DumpManager dumpManager,
             AudioSharingInteractor audioSharingInteractor,
-            JavaAdapter javaAdapter
+            JavaAdapter javaAdapter,
+            VolumeLogger volumeLogger
     ) {
         mContext = context.getApplicationContext();
         mPackageManager = packageManager;
@@ -216,6 +220,7 @@
         mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
         mAudioSharingInteractor = audioSharingInteractor;
         mJavaAdapter = javaAdapter;
+        mVolumeLogger = volumeLogger;
         mAudio = audioManager;
         mNoMan = notificationManager;
         mObserver = new SettingObserver(mWorker);
@@ -293,15 +298,28 @@
         } catch (SecurityException e) {
             Log.w(TAG, "No access to media sessions", e);
         }
-        if (volumeDialogAudioSharingFix()) {
-            Slog.d(TAG, "Start collect volume changes in audio sharing");
-            mJavaAdapter.alwaysCollectFlow(
-                    mAudioSharingInteractor.getVolume(),
-                    this::handleAudioSharingStreamVolumeChanges);
-            mJavaAdapter.alwaysCollectFlow(
-                    mAudioSharingInteractor.isInAudioSharing(),
-                    inSharing -> mInAudioSharing = inSharing);
-        }
+        Function1<Throwable, Unit> errorCallback = (ex) -> {
+            mVolumeLogger.onAudioSharingAvailabilityRequestedError("register()",
+                    ex.getMessage());
+            return null;
+        };
+        var unused =
+                mJavaAdapter.<Context, Boolean>callSuspend(
+                        mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+                        result -> {
+                            if (result) {
+                                Slog.d(TAG, "Start collect volume changes in audio sharing");
+                                mJavaAdapter.alwaysCollectFlow(
+                                        mAudioSharingInteractor.getVolume(),
+                                        volume -> handleAudioSharingStreamVolumeChanges(volume));
+                                mJavaAdapter.alwaysCollectFlow(
+                                        mAudioSharingInteractor.isInAudioSharing(),
+                                        inSharing -> mInAudioSharing = inSharing);
+                            }
+                            return null;
+                        },
+                        errorCallback,
+                        errorCallback);
     }
 
     public void setVolumePolicy(VolumePolicy policy) {
@@ -588,18 +606,34 @@
         mState.activeStream = activeStream;
         Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
         if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
-        final int s =
-                activeStream
-                                < (volumeDialogAudioSharingFix()
-                                        ? DYNAMIC_STREAM_BROADCAST
-                                        : DYNAMIC_STREAM_REMOTE_START_INDEX)
-                        ? activeStream
-                        : -1;
-        if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
-        mAudio.forceVolumeControlStream(s);
+        Function1<Throwable, Unit> errorCallback = (ex) -> {
+            mVolumeLogger.onAudioSharingAvailabilityRequestedError(
+                    "updateActiveStreamW",
+                    ex.getMessage());
+            forceVolumeControlStreamW(activeStream, false);
+            return null;
+        };
+        var unused =
+                mJavaAdapter.<Context, Boolean>callSuspend(
+                        mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+                        result -> {
+                            forceVolumeControlStreamW(activeStream, result);
+                            return null;
+                        },
+                        errorCallback,
+                        errorCallback);
         return true;
     }
 
+    private void forceVolumeControlStreamW(int activeStream,
+            boolean audioSharingVolumeBarAvailable) {
+        final int dynamicStartIdx = audioSharingVolumeBarAvailable ? DYNAMIC_STREAM_BROADCAST
+                : DYNAMIC_STREAM_REMOTE_START_INDEX;
+        final int s = activeStream < dynamicStartIdx ? activeStream : -1;
+        if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
+        mWorker.post(() -> mAudio.forceVolumeControlStream(s));
+    }
+
     private StreamState streamStateW(int stream) {
         StreamState ss = mState.states.get(stream);
         if (ss == null) {
@@ -773,10 +807,26 @@
     }
 
     private void onSetStreamVolumeW(int stream, int level) {
-        if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
-        if (volumeDialogAudioSharingFix() && stream == DYNAMIC_STREAM_BROADCAST) {
-            Slog.d(TAG, "onSetStreamVolumeW set broadcast stream level = " + level);
-            mAudioSharingInteractor.setStreamVolume(level);
+        if (D.BUG) Log.d(TAG, "onSetStreamVolumeW " + stream + " level=" + level);
+
+        if (stream == DYNAMIC_STREAM_BROADCAST) {
+            Function1<Throwable, Unit> errorCallback = (ex) -> {
+                mVolumeLogger.onAudioSharingAvailabilityRequestedError(
+                        "onSetStreamVolumeW",
+                        ex.getMessage());
+                return null;
+            };
+            var unused =
+                    mJavaAdapter.<Context, Boolean>callSuspend(
+                            mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+                            result -> {
+                                if (result) {
+                                    mAudioSharingInteractor.setStreamVolume(level);
+                                }
+                                return null;
+                            },
+                            errorCallback,
+                            errorCallback);
             return;
         }
         if (stream >= DYNAMIC_STREAM_REMOTE_START_INDEX) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index bd4c463..a4e46f6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -34,6 +34,7 @@
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL;
 import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder;
+import static com.android.settingslib.flags.Flags.audioSharingDeveloperOption;
 import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
 import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -121,9 +122,9 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.haptics.slider.HapticSlider;
+import com.android.systemui.haptics.slider.HapticSliderPlugin;
 import com.android.systemui.haptics.slider.HapticSliderViewBinder;
 import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig;
-import com.android.systemui.haptics.slider.HapticSliderPlugin;
 import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig;
 import com.android.systemui.media.dialog.MediaOutputDialogManager;
 import com.android.systemui.plugins.VolumeDialog;
@@ -1685,10 +1686,10 @@
             }
 
             // Always show the stream for audio sharing if it exists.
-            if (volumeDialogAudioSharingFix()
+            if ((volumeDialogAudioSharingFix() || audioSharingDeveloperOption())
                     && row.ss != null
                     && mContext.getString(R.string.audio_sharing_description)
-                            .equals(row.ss.remoteLabel)) {
+                    .equals(row.ss.remoteLabel)) {
                 return true;
             }
 
@@ -1894,9 +1895,9 @@
             if (!ss.dynamic) continue;
             mDynamic.put(stream, true);
             if (findRow(stream) == null) {
-                if (volumeDialogAudioSharingFix()
-                        && mContext.getString(R.string.audio_sharing_description)
-                                .equals(ss.remoteLabel)) {
+                if ((volumeDialogAudioSharingFix() || audioSharingDeveloperOption())
+                        && (mContext.getString(R.string.audio_sharing_description)
+                        .equals(ss.remoteLabel))) {
                     addRow(
                             stream,
                             R.drawable.ic_volume_media_bt,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 536403c..3ce1bde 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.volume;
 
-import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
-
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.Log;
@@ -28,7 +26,12 @@
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.volume.domain.interactor.AudioSharingInteractor;
+import com.android.systemui.volume.shared.VolumeLogger;
+
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
 
 import java.io.PrintWriter;
 
@@ -44,16 +47,22 @@
     private VolumeDialogComponent mVolumeComponent;
     private AudioSharingInteractor mAudioSharingInteractor;
     private AudioRepository mAudioRepository;
+    private JavaAdapter mJavaAdapter;
+    private VolumeLogger mVolumeLogger;
 
     @Inject
     public VolumeUI(Context context,
             VolumeDialogComponent volumeDialogComponent,
             AudioRepository audioRepository,
-            AudioSharingInteractor audioSharingInteractor) {
+            AudioSharingInteractor audioSharingInteractor,
+            JavaAdapter javaAdapter,
+            VolumeLogger volumeLogger) {
         mContext = context;
         mVolumeComponent = volumeDialogComponent;
         mAudioRepository = audioRepository;
         mAudioSharingInteractor = audioSharingInteractor;
+        mJavaAdapter = javaAdapter;
+        mVolumeLogger = volumeLogger;
     }
 
     @Override
@@ -67,9 +76,22 @@
 
         mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
         setDefaultVolumeController();
-        if (volumeDialogAudioSharingFix()) {
-            mAudioSharingInteractor.handlePrimaryGroupChange();
-        }
+        Function1<Throwable, Unit> errorCallback = (ex) -> {
+            mVolumeLogger.onAudioSharingAvailabilityRequestedError("start()",
+                    ex.getMessage());
+            return null;
+        };
+        var unused =
+                mJavaAdapter.<Context, Boolean>callSuspend(
+                        mAudioSharingInteractor::audioSharingVolumeBarAvailable, mContext,
+                        result -> {
+                            if (result) {
+                                mAudioSharingInteractor.handlePrimaryGroupChange();
+                            }
+                            return null;
+                        },
+                        errorCallback,
+                        errorCallback);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
index d5b8597..d71ddb3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
@@ -86,7 +86,10 @@
             @Background coroutineContext: CoroutineContext,
             volumeLogger: VolumeLogger,
         ): AudioSharingRepository =
-            if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
+            if (
+                (Flags.enableLeAudioSharing() || Flags.audioSharingDeveloperOption()) &&
+                    localBluetoothManager != null
+            ) {
                 AudioSharingRepositoryImpl(
                     contentResolver,
                     localBluetoothManager,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
index 1c80887..f6f1e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioSharingModule.kt
@@ -36,7 +36,7 @@
             impl: Lazy<AudioSharingInteractorImpl>,
             emptyImpl: Lazy<AudioSharingInteractorEmptyImpl>,
         ): AudioSharingInteractor =
-            if (Flags.volumeDialogAudioSharingFix()) {
+            if (Flags.volumeDialogAudioSharingFix() || Flags.audioSharingDeveloperOption()) {
                 impl.get()
             } else {
                 emptyImpl.get()
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/domain/interactor/VolumeDialogSlidersInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
index 7af4258..c904ac5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/domain/interactor/VolumeDialogSlidersInteractor.kt
@@ -35,6 +35,7 @@
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.runningReduce
 import kotlinx.coroutines.flow.stateIn
 
 private const val DEFAULT_STREAM = AudioManager.STREAM_MUSIC
@@ -54,13 +55,17 @@
         volumeDialogStateInteractor.volumeDialogState
             .filter { it.streamModels.isNotEmpty() }
             .map { stateModel ->
-                stateModel.streamModels.values
-                    .filter { streamModel -> shouldShowSliders(stateModel, streamModel) }
-                    .sortedWith(streamsSorter)
+                val sliderTypes =
+                    stateModel.streamModels.values
+                        .filter { streamModel -> shouldShowSliders(stateModel, streamModel) }
+                        .sortedWith(streamsSorter)
+                        .map { model -> model.toType() }
+                LinkedHashSet(sliderTypes)
             }
-            .map { models ->
-                val sliderTypes: List<VolumeDialogSliderType> =
-                    models.map { model -> model.toType() }
+            .runningReduce { sliderTypes, newSliderTypes ->
+                newSliderTypes.apply { addAll(sliderTypes) }
+            }
+            .map { sliderTypes ->
                 VolumeDialogSlidersModel(
                     slider = sliderTypes.first(),
                     floatingSliders = sliderTypes.drop(1),
@@ -84,7 +89,7 @@
 
             // Always show the stream for audio sharing if it exists.
             if (
-                Flags.volumeDialogAudioSharingFix() &&
+                (Flags.volumeDialogAudioSharingFix() || Flags.audioSharingDeveloperOption()) &&
                     streamModel.stream == VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST
             ) {
                 return true
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/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
index 293be94..7da041e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioSharingInteractor.kt
@@ -17,8 +17,12 @@
 package com.android.systemui.volume.domain.interactor
 
 import android.bluetooth.BluetoothCsipSetCoordinator
+import android.content.Context
 import android.media.AudioManager.STREAM_MUSIC
 import androidx.annotation.IntRange
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.flags.Flags
 import com.android.settingslib.volume.data.repository.AudioSharingRepository
 import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MAX
 import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MIN
@@ -38,7 +42,6 @@
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 interface AudioSharingInteractor {
@@ -54,6 +57,8 @@
     /** Audio sharing secondary headset max volume. */
     val volumeMax: Int
 
+    suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean
+
     /** Set the volume of the secondary headset in audio sharing. */
     fun setStreamVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
@@ -78,7 +83,7 @@
     @Application private val coroutineScope: CoroutineScope,
     @Background private val backgroundCoroutineContext: CoroutineContext,
     private val audioVolumeInteractor: AudioVolumeInteractor,
-    private val audioSharingRepository: AudioSharingRepository
+    private val audioSharingRepository: AudioSharingRepository,
 ) : AudioSharingInteractor {
     override val isInAudioSharing: Flow<Boolean> = audioSharingRepository.inAudioSharing
 
@@ -95,6 +100,12 @@
 
     override val volumeMax: Int = AUDIO_SHARING_VOLUME_MAX
 
+    override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+        withContext(backgroundCoroutineContext) {
+            (Flags.volumeDialogAudioSharingFix() && BluetoothUtils.isAudioSharingEnabled()) ||
+                BluetoothUtils.isAudioSharingPreviewEnabled(context.contentResolver)
+        }
+
     override fun setStreamVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
         level: Int
@@ -141,6 +152,9 @@
     override val volumeMin: Int = EMPTY_VOLUME
     override val volumeMax: Int = EMPTY_VOLUME
 
+    override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+        false
+
     override fun setStreamVolume(
         @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
         level: Int
diff --git a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
index d6b159e..3847df6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
@@ -41,7 +41,7 @@
                 str1 = audioStream.toString()
                 int1 = volume
             },
-            { "Set volume: stream=$str1 volume=$int1" }
+            { "Set volume: stream=$str1 volume=$int1" },
         )
     }
 
@@ -53,7 +53,7 @@
                 str1 = audioStream.toString()
                 int1 = model.volume
             },
-            { "Volume update received: stream=$str1 volume=$int1" }
+            { "Volume update received: stream=$str1 volume=$int1" },
         )
     }
 
@@ -62,7 +62,7 @@
             TAG,
             LogLevel.DEBUG,
             { bool1 = state },
-            { "Audio sharing state update: state=$bool1" }
+            { "Audio sharing state update: state=$bool1" },
         )
     }
 
@@ -71,7 +71,7 @@
             TAG,
             LogLevel.DEBUG,
             { int1 = groupId },
-            { "Secondary group id in audio sharing update: groupId=$int1" }
+            { "Secondary group id in audio sharing update: groupId=$int1" },
         )
     }
 
@@ -80,11 +80,23 @@
             TAG,
             LogLevel.DEBUG,
             { str1 = map.toString() },
-            { "Volume map update: map=$str1" }
+            { "Volume map update: map=$str1" },
         )
     }
 
     override fun onSetDeviceVolumeRequested(volume: Int) {
         logBuffer.log(TAG, LogLevel.DEBUG, { int1 = volume }, { "Set device volume: volume=$int1" })
     }
+
+    override fun onAudioSharingAvailabilityRequestedError(requestFrom: String, e: String) {
+        logBuffer.log(
+            TAG,
+            LogLevel.WARNING,
+            {
+                str1 = requestFrom
+                str1 = e
+            },
+            { "$str1, fail to check audio sharing availability: e=$str2" },
+        )
+    }
 }
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/communal/data/backup/CommunalBackupHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
index 6e9b24f..4ca84c58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
@@ -37,7 +37,6 @@
 import java.io.File
 import java.io.FileInputStream
 import java.io.FileOutputStream
-import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -63,22 +62,18 @@
             Room.inMemoryDatabaseBuilder(context, CommunalDatabase::class.java)
                 .allowMainThreadQueries()
                 .build()
+        onTeardown { database.close() }
         CommunalDatabase.setInstance(database)
 
         dao = database.communalWidgetDao()
         backupUtils = CommunalBackupUtils(context)
 
         backupDataFile = File(context.cacheDir, "backup_data_file")
+        onTeardown { backupDataFile.delete() }
 
         underTest = CommunalBackupHelper(UserHandle.SYSTEM, backupUtils)
     }
 
-    @After
-    fun teardown() {
-        backupDataFile.delete()
-        database.close()
-    }
-
     @Test
     @EnableFlags(Flags.FLAG_COMMUNAL_HUB)
     fun backupAndRestoreCommunalHub() {
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
index f8d8481..a9b6dd1 100644
--- 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
@@ -26,6 +26,7 @@
 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.testCase
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 import com.google.common.truth.Truth.assertThat
@@ -37,7 +38,7 @@
 @RunWith(AndroidJUnit4::class)
 class ShortcutCustomizationViewModelTest : SysuiTestCase() {
 
-    private val kosmos = Kosmos()
+    private val kosmos = Kosmos().also { it.testCase = this }
     private val testScope = kosmos.testScope
     private val viewModel = kosmos.shortcutCustomizationViewModelFactory.create()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 7383faf..feae901 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -278,7 +278,11 @@
         testScope.runTest {
             fakeSystemSource.setGroups(
                 groupWithShortcutLabels("first Foo shortcut1", "first bar shortcut1"),
-                groupWithShortcutLabels("second foO shortcut2", "second bar shortcut2"),
+                groupWithShortcutLabels(
+                    "second foO shortcut2",
+                    "second bar shortcut2",
+                    groupLabel = SECOND_SIMPLE_GROUP_LABEL,
+                ),
             )
             fakeMultiTaskingSource.setGroups(
                 groupWithShortcutLabels("third FoO shortcut1", "third bar shortcut1")
@@ -298,7 +302,10 @@
                             ShortcutCategory(
                                 System,
                                 subCategoryWithShortcutLabels("first Foo shortcut1"),
-                                subCategoryWithShortcutLabels("second foO shortcut2"),
+                                subCategoryWithShortcutLabels(
+                                    "second foO shortcut2",
+                                    subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
+                                ),
                             ),
                     ),
                     ShortcutCategoryUi(
@@ -380,16 +387,23 @@
             assertThat(activeUiState.defaultSelectedCategory).isInstanceOf(CurrentApp::class.java)
         }
 
-    private fun groupWithShortcutLabels(vararg shortcutLabels: String) =
-        KeyboardShortcutGroup(SIMPLE_GROUP_LABEL, shortcutLabels.map { simpleShortcutInfo(it) })
-            .apply { packageName = "test.package.name" }
+    private fun groupWithShortcutLabels(
+        vararg shortcutLabels: String,
+        groupLabel: String = FIRST_SIMPLE_GROUP_LABEL,
+    ) =
+        KeyboardShortcutGroup(groupLabel, shortcutLabels.map { simpleShortcutInfo(it) }).apply {
+            packageName = "test.package.name"
+        }
 
     private fun simpleShortcutInfo(label: String) =
         KeyboardShortcutInfo(label, KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON)
 
-    private fun subCategoryWithShortcutLabels(vararg shortcutLabels: String) =
+    private fun subCategoryWithShortcutLabels(
+        vararg shortcutLabels: String,
+        subCategoryLabel: String = FIRST_SIMPLE_GROUP_LABEL,
+    ) =
         ShortcutSubCategory(
-            label = SIMPLE_GROUP_LABEL,
+            label = subCategoryLabel,
             shortcuts = shortcutLabels.map { simpleShortcut(it) },
         )
 
@@ -402,6 +416,7 @@
         }
 
     companion object {
-        private const val SIMPLE_GROUP_LABEL = "simple group"
+        private const val FIRST_SIMPLE_GROUP_LABEL = "simple group 1"
+        private const val SECOND_SIMPLE_GROUP_LABEL = "simple group 2"
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt
new file mode 100644
index 0000000..c8faa81
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.reardisplay
+
+import android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_RDM_V2
+import android.hardware.display.rearDisplay
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.deviceStateManager
+import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.rearDisplayInnerDialogDelegateFactory
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import org.junit.Before
+import org.junit.Test
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayCoreStartableTest */
+@SmallTest
+@kotlinx.coroutines.ExperimentalCoroutinesApi
+class RearDisplayCoreStartableTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val mockDelegate: RearDisplayInnerDialogDelegate = mock()
+    private val mockDialog: SystemUIDialog = mock()
+
+    private val fakeRearDisplayStateInteractor = FakeRearDisplayStateInteractor(kosmos)
+    private val impl =
+        RearDisplayCoreStartable(
+            mContext,
+            kosmos.deviceStateManager,
+            fakeRearDisplayStateInteractor,
+            kosmos.rearDisplayInnerDialogDelegateFactory,
+            kosmos.testScope,
+        )
+
+    @Before
+    fun setup() {
+        whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR)
+        whenever(kosmos.rearDisplay.displayAdjustments)
+            .thenReturn(mContext.display.displayAdjustments)
+        whenever(kosmos.rearDisplayInnerDialogDelegateFactory.create(any(), any()))
+            .thenReturn(mockDelegate)
+        whenever(mockDelegate.createDialog()).thenReturn(mockDialog)
+    }
+
+    @Test
+    @DisableFlags(FLAG_DEVICE_STATE_RDM_V2)
+    fun testWhenFlagDisabled() =
+        kosmos.runTest {
+            impl.use {
+                it.start()
+                assertThat(impl.stateChangeListener).isNull()
+            }
+        }
+
+    @Test
+    @EnableFlags(FLAG_DEVICE_STATE_RDM_V2)
+    fun testShowAndDismissDialog() =
+        kosmos.runTest {
+            impl.use {
+                it.start()
+                fakeRearDisplayStateInteractor.emitRearDisplay()
+                verify(mockDialog).show()
+                verify(mockDialog, never()).dismiss()
+
+                fakeRearDisplayStateInteractor.emitDisabled()
+                verify(mockDialog).dismiss()
+            }
+        }
+
+    private class FakeRearDisplayStateInteractor(private val kosmos: Kosmos) :
+        RearDisplayStateInteractor {
+        private val stateFlow = MutableSharedFlow<RearDisplayStateInteractor.State>()
+
+        suspend fun emitRearDisplay() =
+            stateFlow.emit(RearDisplayStateInteractor.State.Enabled(kosmos.rearDisplay))
+
+        suspend fun emitDisabled() = stateFlow.emit(RearDisplayStateInteractor.State.Disabled)
+
+        override val state: Flow<RearDisplayStateInteractor.State>
+            get() = stateFlow
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt
new file mode 100644
index 0000000..6058880
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.reardisplay
+
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.systemUIDialogDotFactory
+import com.android.systemui.testKosmos
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.mock
+
+/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayInnerDialogDelegateTest */
+@SmallTest
+@TestableLooper.RunWithLooper
+class RearDisplayInnerDialogDelegateTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+
+    @Test
+    fun testShowAndDismissDialog() {
+        val dialogDelegate =
+            RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) {}
+
+        val dialog = dialogDelegate.createDialog()
+        dialog.show()
+        assertTrue(dialog.isShowing)
+
+        dialog.dismiss()
+        assertFalse(dialog.isShowing)
+    }
+
+    @Test
+    fun testCancel() {
+        val mockCallback = mock<Runnable>()
+        RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) {
+                mockCallback.run()
+            }
+            .createDialog()
+            .apply {
+                show()
+                findViewById<View>(R.id.button_cancel).performClick()
+                verify(mockCallback).run()
+            }
+    }
+}
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/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index c9ada7e..b142fc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -155,6 +155,7 @@
 import com.android.systemui.shade.ShadeControllerImpl;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.shade.ShadeLogger;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
 import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyboardShortcutListSearch;
@@ -174,7 +175,6 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
 import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
-import com.android.systemui.statusbar.core.StatusBarOrchestrator;
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -372,7 +372,7 @@
     @Mock private EmergencyGestureIntentFactory mEmergencyGestureIntentFactory;
     @Mock private NotificationSettingsInteractor mNotificationSettingsInteractor;
     @Mock private ViewCaptureAwareWindowManager mViewCaptureAwareWindowManager;
-    @Mock private StatusBarOrchestrator mStatusBarOrchestrator;
+    @Mock private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
     private final FakeGlobalSettings mFakeGlobalSettings = new FakeGlobalSettings();
@@ -607,6 +607,7 @@
                 mShadeController,
                 mWindowRootViewVisibilityInteractor,
                 mStatusBarKeyguardViewManager,
+                () -> mStatusBarLongPressGestureDetector,
                 mViewMediatorCallback,
                 mInitController,
                 new Handler(TestableLooper.get(this).getLooper()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 638f195..69efa87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -40,14 +40,13 @@
 import com.android.systemui.plugins.fakeDarkIconDispatcher
 import com.android.systemui.res.R
 import com.android.systemui.scene.ui.view.WindowRootView
-import com.android.systemui.shade.LongPressGestureDetector
 import com.android.systemui.shade.ShadeControllerImpl
 import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.StatusBarLongPressGestureDetector
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore
-import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore
 import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
@@ -98,7 +97,7 @@
     @Mock private lateinit var windowRootView: Provider<WindowRootView>
     @Mock private lateinit var shadeLogger: ShadeLogger
     @Mock private lateinit var viewUtil: ViewUtil
-    @Mock private lateinit var longPressGestureDetector: LongPressGestureDetector
+    @Mock private lateinit var mStatusBarLongPressGestureDetector: StatusBarLongPressGestureDetector
     private lateinit var statusBarWindowStateController: StatusBarWindowStateController
 
     private lateinit var view: PhoneStatusBarView
@@ -395,7 +394,7 @@
                 shadeControllerImpl,
                 shadeViewController,
                 panelExpansionInteractor,
-                { longPressGestureDetector },
+                { mStatusBarLongPressGestureDetector },
                 windowRootView,
                 shadeLogger,
                 viewUtil,
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
index 796ec94..45dcb28 100644
--- a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt
@@ -16,7 +16,12 @@
 
 package android.hardware.display
 
+import android.view.Display
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import org.mockito.kotlin.mock
 
 val Kosmos.displayManager by Kosmos.Fixture { mock<DisplayManager>() }
+
+val Kosmos.defaultDisplay: Display by Kosmos.Fixture { mock<Display>() }
+
+val Kosmos.rearDisplay: Display by Kosmos.Fixture { mock<Display>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
index 9c55820..b8a095e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt
@@ -18,6 +18,7 @@
 
 import android.hardware.devicestate.DeviceState
 import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY
+import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY
 import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED
@@ -44,7 +45,7 @@
                     .setSystemProperties(
                         setOf(
                             PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
-                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
                         )
                     )
                     .setPhysicalProperties(
@@ -57,7 +58,7 @@
                     .setSystemProperties(
                         setOf(
                             PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
-                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
                         )
                     )
                     .setPhysicalProperties(
@@ -70,14 +71,14 @@
                     .setSystemProperties(
                         setOf(
                             PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
-                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP
+                            PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP,
                         )
                     )
                     .setPhysicalProperties(
                         setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED)
                     )
                     .build()
-            )
+            ),
         )
     }
 
@@ -88,7 +89,7 @@
                 .setSystemProperties(
                     setOf(
                         PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
-                        PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
+                        PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE,
                     )
                 )
                 .setPhysicalProperties(
@@ -105,7 +106,7 @@
                 .setSystemProperties(
                     setOf(
                         PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY,
-                        PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE
+                        PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE,
                     )
                 )
                 .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN))
@@ -120,7 +121,22 @@
                 .setSystemProperties(
                     setOf(
                         PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
-                        PROPERTY_FEATURE_REAR_DISPLAY
+                        PROPERTY_FEATURE_REAR_DISPLAY,
+                    )
+                )
+                .build()
+        )
+    }
+
+val Kosmos.rearDisplayOuterDefaultDeviceState by
+    Kosmos.Fixture {
+        DeviceState(
+            DeviceState.Configuration.Builder(5 /* identifier */, "REAR_DISPLAY")
+                .setSystemProperties(
+                    setOf(
+                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY,
+                        PROPERTY_FEATURE_REAR_DISPLAY,
+                        PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT,
                     )
                 )
                 .build()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt
new file mode 100644
index 0000000..6f59855
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.reardisplay.RearDisplayInnerDialogDelegate
+import org.mockito.kotlin.mock
+
+val Kosmos.rearDisplayInnerDialogDelegateFactory by
+    Kosmos.Fixture { mock<RearDisplayInnerDialogDelegate.Factory>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
index 2198e04..e36ad42 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/brightness/ui/viewmodel/BrightnessSliderViewModelKosmos.kt
@@ -21,7 +21,7 @@
 import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor
-import com.android.systemui.kosmos.brightnessWarningToast
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
 
 val Kosmos.brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory by
     Kosmos.Fixture {
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 903bc8e..9cb15c5 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
@@ -136,7 +136,11 @@
     }
 
 val Kosmos.shortcutHelperCategoriesInteractor by
-    Kosmos.Fixture { ShortcutHelperCategoriesInteractor(defaultShortcutCategoriesRepository) }
+    Kosmos.Fixture {
+        ShortcutHelperCategoriesInteractor(defaultShortcutCategoriesRepository) {
+            customShortcutCategoriesRepository
+        }
+    }
 
 val Kosmos.shortcutHelperViewModel by
     Kosmos.Fixture {
@@ -162,7 +166,8 @@
         }
     }
 
-val Kosmos.shortcutCustomizationInteractor by Kosmos.Fixture { ShortcutCustomizationInteractor() }
+val Kosmos.shortcutCustomizationInteractor by
+    Kosmos.Fixture { ShortcutCustomizationInteractor(customShortcutCategoriesRepository) }
 
 val Kosmos.shortcutCustomizationViewModelFactory by
     Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
index d33d594..76e2cc8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModelKosmos.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.keyguardSmartspaceViewModel by
@@ -28,5 +29,6 @@
             smartspaceController = mock(),
             keyguardClockViewModel = keyguardClockViewModel,
             smartspaceInteractor = keyguardSmartspaceInteractor,
+            shadeInteractor = shadeInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
index f43841b..72cb1df 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt
@@ -3,9 +3,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.settings.brightness.ui.BrightnessWarningToast
-
-import com.android.systemui.util.mockito.mock
 import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.test.StandardTestDispatcher
@@ -41,9 +38,6 @@
     testScope.backgroundScope.coroutineContext
 }
 var Kosmos.mainCoroutineContext: CoroutineContext by Fixture { testScope.coroutineContext }
-var Kosmos.brightnessWarningToast: BrightnessWarningToast by Kosmos.Fixture {
-    mock<BrightnessWarningToast>()
-}
 
 /**
  * Run this test body with a [Kosmos] as receiver, and using the [testScope] currently installed in
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 d1303d2..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,6 +71,8 @@
 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
@@ -183,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/settings/BrightnessSliderControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
index aac122c..5d146fb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/BrightnessSliderControllerKosmos.kt
@@ -21,9 +21,9 @@
 import com.android.systemui.haptics.msdl.msdlPlayer
 import com.android.systemui.haptics.vibratorHelper
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.brightnessWarningToast
 import com.android.systemui.plugins.activityStarter
 import com.android.systemui.settings.brightness.BrightnessSliderController
+import com.android.systemui.settings.brightness.ui.brightnessWarningToast
 import com.android.systemui.util.time.systemClock
 
 /** This factory creates empty mocks. */
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt
new file mode 100644
index 0000000..d9acb52
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToastKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.settings.brightness.ui
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.brightnessWarningToast: BrightnessWarningToast by
+    Kosmos.Fixture { mock<BrightnessWarningToast>() }
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/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
new file mode 100644
index 0000000..7b4b047
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.disableflags.domain.interactor
+
+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/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/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
index 65f4122..21a910b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.util.settings;
 
+import static com.android.systemui.util.settings.JavaAdapter.newCoroutineScope;
+
 import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
 
 import android.annotation.NonNull;
@@ -25,6 +27,7 @@
 import android.net.Uri;
 
 import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.CoroutineScope;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -34,7 +37,7 @@
 public class FakeGlobalSettings implements GlobalSettings {
     private final Map<String, String> mValues = new HashMap<>();
     private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
-    private final CoroutineDispatcher mDispatcher;
+    private final CoroutineScope mSettingsScope;
 
     public static final Uri CONTENT_URI = Uri.parse("content://settings/fake_global");
 
@@ -44,11 +47,15 @@
      */
     @Deprecated
     public FakeGlobalSettings() {
-        mDispatcher = StandardTestDispatcher(/* scheduler = */ null, /* name = */ null);
+        CoroutineDispatcher dispatcher = StandardTestDispatcher(
+                /* scheduler = */ null,
+                /* name = */ null
+        );
+        mSettingsScope = newCoroutineScope(dispatcher);
     }
 
     public FakeGlobalSettings(CoroutineDispatcher dispatcher) {
-        mDispatcher = dispatcher;
+        mSettingsScope = newCoroutineScope(dispatcher);
     }
 
     @NonNull
@@ -61,8 +68,8 @@
 
     @NonNull
     @Override
-    public CoroutineDispatcher getBackgroundDispatcher() {
-        return mDispatcher;
+    public CoroutineScope getSettingsScope() {
+        return mSettingsScope;
     }
 
     @Override
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
index 35fa2af..78b78ca 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt
@@ -19,5 +19,14 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.testDispatcher
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
 
 val Kosmos.fakeGlobalSettings: FakeGlobalSettings by Fixture { FakeGlobalSettings(testDispatcher) }
+
+object JavaAdapter {
+    @JvmStatic
+    fun newCoroutineScope(context: CoroutineContext): CoroutineScope {
+        return CoroutineScope(context)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
index e5d113b..a357275 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt
@@ -24,6 +24,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.util.settings.SettingsProxy.CurrentUserIdProvider
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestDispatcher
@@ -33,7 +34,7 @@
     private val contentObservers = mutableMapOf<SettingsKey, MutableList<ContentObserver>>()
     private val contentObserversAllUsers = mutableMapOf<String, MutableList<ContentObserver>>()
 
-    override val backgroundDispatcher: CoroutineDispatcher
+    override val settingsScope: CoroutineScope
 
     @UserIdInt override var userId = UserHandle.USER_CURRENT
     override val currentUserProvider: CurrentUserIdProvider
@@ -43,17 +44,17 @@
       by main test scope."""
     )
     constructor() {
-        backgroundDispatcher = StandardTestDispatcher(scheduler = null, name = null)
+        settingsScope = CoroutineScope(StandardTestDispatcher(scheduler = null, name = null))
         currentUserProvider = CurrentUserIdProvider { userId }
     }
 
     constructor(dispatcher: CoroutineDispatcher) {
-        backgroundDispatcher = dispatcher
+        settingsScope = CoroutineScope(dispatcher)
         currentUserProvider = CurrentUserIdProvider { userId }
     }
 
     constructor(dispatcher: CoroutineDispatcher, currentUserProvider: CurrentUserIdProvider) {
-        backgroundDispatcher = dispatcher
+        settingsScope = CoroutineScope(dispatcher)
         this.currentUserProvider = currentUserProvider
     }
 
@@ -77,7 +78,7 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
         if (userHandle == UserHandle.USER_ALL) {
             contentObserversAllUsers
@@ -107,31 +108,31 @@
     override suspend fun registerContentObserver(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) = suspendAdvanceDispatcher {
         super<UserSettingsProxy>.registerContentObserver(
             uri,
             notifyForDescendants,
-            settingsObserver
+            settingsObserver,
         )
     }
 
     override fun registerContentObserverAsync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ): Job = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverAsync(
             uri,
             notifyForDescendants,
-            settingsObserver
+            settingsObserver,
         )
     }
 
     override suspend fun registerContentObserverForUser(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) = suspendAdvanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUser(name, settingsObserver, userHandle)
     }
@@ -139,12 +140,12 @@
     override fun registerContentObserverForUserAsync(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ): Job = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUserAsync(
             name,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -156,7 +157,7 @@
     override suspend fun registerContentObserverForUser(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) = suspendAdvanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUser(uri, settingsObserver, userHandle)
     }
@@ -164,12 +165,12 @@
     override fun registerContentObserverForUserAsync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ): Job = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUserAsync(
             uri,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -177,13 +178,13 @@
         uri: Uri,
         settingsObserver: ContentObserver,
         userHandle: Int,
-        registered: Runnable
+        registered: Runnable,
     ): Job = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUserAsync(
             uri,
             settingsObserver,
             userHandle,
-            registered
+            registered,
         )
     }
 
@@ -191,13 +192,13 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) = suspendAdvanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUser(
             name,
             notifyForDescendants,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -205,13 +206,13 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUserAsync(
             name,
             notifyForDescendants,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -219,13 +220,13 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ): Job = advanceDispatcher {
         super<UserSettingsProxy>.registerContentObserverForUserAsync(
             uri,
             notifyForDescendants,
             settingsObserver,
-            userHandle
+            userHandle,
         )
     }
 
@@ -259,7 +260,7 @@
         tag: String?,
         makeDefault: Boolean,
         userHandle: Int,
-        overrideableByRestore: Boolean
+        overrideableByRestore: Boolean,
     ): Boolean {
         val key = SettingsKey(userHandle, getUriFor(name).toString())
         values[key] = value
@@ -275,7 +276,7 @@
         name: String,
         value: String?,
         tag: String?,
-        makeDefault: Boolean
+        makeDefault: Boolean,
     ): Boolean {
         return putString(name, value)
     }
@@ -293,8 +294,9 @@
         return result
     }
 
+    @OptIn(ExperimentalStdlibApi::class)
     private fun testDispatcherRunCurrent() {
-        val testDispatcher = backgroundDispatcher as? TestDispatcher
+        val testDispatcher = settingsScope.coroutineContext[CoroutineDispatcher] as? TestDispatcher
         testDispatcher?.scheduler?.runCurrent()
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
new file mode 100644
index 0000000..1fb5e77
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/FakeAudioSharingInteractor.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.domain.interactor
+
+import android.content.Context
+import androidx.annotation.IntRange
+import com.android.dream.lowlight.dagger.qualifiers.Application
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeAudioSharingInteractor : AudioSharingInteractor {
+    private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    private val mutableVolume: MutableStateFlow<Int?> = MutableStateFlow(null)
+    private var audioSharingVolumeBarAvailable = false
+
+    override val isInAudioSharing: Flow<Boolean> = mutableInAudioSharing
+    override val volume: Flow<Int?> = mutableVolume
+    override val volumeMin: Int = AUDIO_SHARING_VOLUME_MIN
+    override val volumeMax: Int = AUDIO_SHARING_VOLUME_MAX
+
+    override suspend fun audioSharingVolumeBarAvailable(@Application context: Context): Boolean =
+        audioSharingVolumeBarAvailable
+
+    override fun setStreamVolume(
+        @IntRange(from = AUDIO_SHARING_VOLUME_MIN.toLong(), to = AUDIO_SHARING_VOLUME_MAX.toLong())
+        level: Int
+    ) {}
+
+    override fun handlePrimaryGroupChange() {}
+
+    fun setInAudioSharing(state: Boolean) {
+        mutableInAudioSharing.value = state
+    }
+
+    fun setVolume(volume: Int?) {
+        mutableVolume.value = volume
+    }
+
+    fun setAudioSharingVolumeBarAvailable(available: Boolean) {
+        audioSharingVolumeBarAvailable = available
+    }
+
+    companion object {
+        const val AUDIO_SHARING_VOLUME_MIN = 0
+        const val AUDIO_SHARING_VOLUME_MAX = 255
+    }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 869d854..9b71f80 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -30,6 +30,8 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runner.Runner;
@@ -229,7 +231,9 @@
             s.evaluate();
             onAfter(description, scope, order, null);
         } catch (Throwable t) {
-            if (onAfter(description, scope, order, t)) {
+            var shouldReportFailure = RavenwoodCommonUtils.runIgnoringException(
+                    () -> onAfter(description, scope, order, t));
+            if (shouldReportFailure == null || shouldReportFailure) {
                 throw t;
             }
         }
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 678a97b..1c1f157 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -22,6 +22,8 @@
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault;
 
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +41,7 @@
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -154,6 +157,13 @@
     private static RavenwoodAwareTestRunner sRunner;
     private static RavenwoodSystemProperties sProps;
 
+    private static final int DEFAULT_TARGET_SDK_LEVEL = VERSION_CODES.CUR_DEVELOPMENT;
+    private static final String DEFAULT_PACKAGE_NAME = "com.android.ravenwoodtests.defaultname";
+
+    private static int sTargetSdkLevel;
+    private static String sTestPackageName;
+    private static String sTargetPackageName;
+
     /**
      * Initialize the global environment.
      */
@@ -235,9 +245,22 @@
         System.setProperty("android.junit.runner",
                 "androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
 
+        loadRavenwoodProperties();
+
         assertMockitoVersion();
     }
 
+    private static void loadRavenwoodProperties() {
+        var props = RavenwoodSystemProperties.readProperties("ravenwood.properties");
+
+        sTargetSdkLevel = withDefault(
+                parseNullableInt(props.get("targetSdkVersionInt")), DEFAULT_TARGET_SDK_LEVEL);
+        sTargetPackageName = withDefault(props.get("packageName"), DEFAULT_PACKAGE_NAME);
+        sTestPackageName = withDefault(props.get("instPackageName"), sTargetPackageName);
+
+        // TODO(b/377765941) Read them from the manifest too?
+    }
+
     /**
      * Initialize the environment.
      */
@@ -256,7 +279,9 @@
             initInner(runner.mState.getConfig());
         } catch (Exception th) {
             Log.e(TAG, "init() failed", th);
-            reset();
+
+            RavenwoodCommonUtils.runIgnoringException(()-> reset());
+
             SneakyThrow.sneakyThrow(th);
         }
     }
@@ -267,6 +292,14 @@
             Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
         }
 
+        config.mTargetPackageName = sTargetPackageName;
+        config.mTestPackageName = sTestPackageName;
+        config.mTargetSdkLevel = sTargetSdkLevel;
+
+        Log.i(TAG, "TargetPackageName=" + sTargetPackageName);
+        Log.i(TAG, "TestPackageName=" + sTestPackageName);
+        Log.i(TAG, "TargetSdkLevel=" + sTargetSdkLevel);
+
         RavenwoodRuntimeState.sUid = config.mUid;
         RavenwoodRuntimeState.sPid = config.mPid;
         RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel;
@@ -349,8 +382,11 @@
      * Partially re-initialize after each test method invocation
      */
     public static void reinit() {
-        var config = sRunner.mState.getConfig();
-        Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+        // sRunner could be null, if there was a failure in the initialization.
+        if (sRunner != null) {
+            var config = sRunner.mState.getConfig();
+            Binder.restoreCallingIdentity(packBinderIdentityToken(false, config.mUid, config.mPid));
+        }
     }
 
     private static void initializeCompatIds(RavenwoodConfig config) {
@@ -380,6 +416,9 @@
 
     /**
      * De-initialize.
+     *
+     * Note, we call this method when init() fails too, so this method should deal with
+     * any partially-initialized states.
      */
     public static void reset() {
         if (RAVENWOOD_VERBOSE_LOGGING) {
@@ -411,7 +450,9 @@
             config.mState.mSystemServerContext.cleanUp();
         }
 
-        Looper.getMainLooper().quit();
+        if (Looper.getMainLooper() != null) {
+            Looper.getMainLooper().quit();
+        }
         Looper.clearMainLooperForTest();
 
         ActivityManager.reset$ravenwood();
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 3ed8b0a..619c8e3 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -22,7 +22,6 @@
 import android.annotation.Nullable;
 import android.app.Instrumentation;
 import android.content.Context;
-import android.os.Build;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -30,16 +29,12 @@
 import java.lang.annotation.Target;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * Represents how to configure the ravenwood environment for a test class.
- *
- * If a ravenwood test class has a public static field with the {@link Config} annotation,
- * Ravenwood will extract the config from it and initializes the environment. The type of the
- * field must be of {@link RavenwoodConfig}.
+ * @deprecated This class will be removed. Reach out to g/ravenwood if you need any features in it.
  */
+@Deprecated
 public final class RavenwoodConfig {
     /**
      * Use this to mark a field as the configuration.
@@ -66,7 +61,7 @@
     String mTestPackageName;
     String mTargetPackageName;
 
-    int mTargetSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
+    int mTargetSdkLevel;
 
     final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
 
@@ -91,12 +86,6 @@
         return RavenwoodRule.isOnRavenwood();
     }
 
-    private void setDefaults() {
-        if (mTargetPackageName == null) {
-            mTargetPackageName = mTestPackageName;
-        }
-    }
-
     public static class Builder {
         private final RavenwoodConfig mConfig = new RavenwoodConfig();
 
@@ -120,28 +109,27 @@
         }
 
         /**
-         * Configure the package name of the test, which corresponds to
-         * {@link Instrumentation#getContext()}.
+         * @deprecated no longer used. Package name is set in the build file. (for now)
          */
+        @Deprecated
         public Builder setPackageName(@NonNull String packageName) {
-            mConfig.mTestPackageName = Objects.requireNonNull(packageName);
             return this;
         }
 
         /**
-         * Configure the package name of the target app, which corresponds to
-         * {@link Instrumentation#getTargetContext()}. Defaults to {@link #setPackageName}.
+         * @deprecated no longer used. Package name is set in the build file. (for now)
          */
+        @Deprecated
         public Builder setTargetPackageName(@NonNull String packageName) {
-            mConfig.mTargetPackageName = Objects.requireNonNull(packageName);
             return this;
         }
 
+
         /**
-         * Configure the target SDK level of the test.
+         * @deprecated no longer used. Target SDK level is set in the build file. (for now)
          */
+        @Deprecated
         public Builder setTargetSdkLevel(int sdkLevel) {
-            mConfig.mTargetSdkLevel = sdkLevel;
             return this;
         }
 
@@ -205,7 +193,6 @@
         }
 
         public RavenwoodConfig build() {
-            mConfig.setDefaults();
             return mConfig;
         }
     }
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index bfa3802..f7acd90 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -36,10 +36,8 @@
 import java.util.regex.Pattern;
 
 /**
- * @deprecated Use {@link RavenwoodConfig} to configure the ravenwood environment instead.
- * A {@link RavenwoodRule} is no longer needed for {@link DisabledOnRavenwood}. To get the
- * {@link Context} and {@link Instrumentation}, use
- * {@link androidx.test.platform.app.InstrumentationRegistry} instead.
+ * @deprecated This class is undergoing a major change. Reach out to g/ravenwood if you need
+ * any featues in it.
  */
 @Deprecated
 public final class RavenwoodRule implements TestRule {
@@ -128,11 +126,10 @@
         }
 
         /**
-         * Configure the identity of this process to be the given package name for the duration
-         * of the test. Has no effect on non-Ravenwood environments.
+         * @deprecated no longer used.
          */
+        @Deprecated
         public Builder setPackageName(@NonNull String packageName) {
-            mBuilder.setPackageName(packageName);
             return this;
         }
 
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index 3e4619f..9bd376a 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -52,7 +52,7 @@
             "vendor_dlkm",
     };
 
-    private static Map<String, String> readProperties(String propFile) {
+    static Map<String, String> readProperties(String propFile) {
         // Use an ordered map just for cleaner dump log.
         final Map<String, String> ret = new LinkedHashMap<>();
         try {
@@ -60,7 +60,7 @@
                     .map(String::trim)
                     .filter(s -> !s.startsWith("#"))
                     .map(s -> s.split("\\s*=\\s*", 2))
-                    .filter(a -> a.length == 2)
+                    .filter(a -> a.length == 2 && a[1].length() > 0)
                     .forEach(a -> ret.put(a[0], a[1]));
         } catch (IOException e) {
             throw new RuntimeException(e);
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
index 520f050..2a04d44 100644
--- a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
@@ -30,6 +30,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
+import java.util.function.Supplier;
 
 public class RavenwoodCommonUtils {
     private static final String TAG = "RavenwoodCommonUtils";
@@ -277,11 +278,55 @@
                 (isStatic ? "static" : "")));
     }
 
+    /**
+     * Run a supplier and swallow the exception, if any.
+     *
+     * It's a dangerous function. Only use it in an exception handler where we don't want to crash.
+     */
+    @Nullable
+    public static <T> T runIgnoringException(@NonNull Supplier<T> s) {
+        try {
+            return s.get();
+        } catch (Throwable th) {
+            log(TAG, "Warning: Exception detected! " + getStackTraceString(th));
+        }
+        return null;
+    }
+
+    /**
+     * Run a runnable and swallow the exception, if any.
+     *
+     * It's a dangerous function. Only use it in an exception handler where we don't want to crash.
+     */
+    public static void runIgnoringException(@NonNull Runnable r) {
+        runIgnoringException(() -> {
+            r.run();
+            return null;
+        });
+    }
+
     @NonNull
-    public static String getStackTraceString(@Nullable Throwable th) {
+    public static String getStackTraceString(@NonNull Throwable th) {
         StringWriter stringWriter = new StringWriter();
         PrintWriter writer = new PrintWriter(stringWriter);
         th.printStackTrace(writer);
         return stringWriter.toString();
     }
+
+    /** Same as {@link Integer#parseInt(String)} but accepts null and returns null. */
+    @Nullable
+    public static Integer parseNullableInt(@Nullable String value) {
+        if (value == null) {
+            return null;
+        }
+        return Integer.parseInt(value);
+    }
+
+    /**
+     * @return {@code value} if it's non-null. Otherwise, returns {@code def}.
+     */
+    @Nullable
+    public static <T> T withDefault(@Nullable T value, @Nullable T def) {
+        return value != null ? value : def;
+    }
 }
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
index 41e45e5..31e3bcc 100644
--- a/ravenwood/tests/bivalentinst/Android.bp
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -27,6 +27,9 @@
         "junit",
         "truth",
     ],
+
+    package_name: "com.android.ravenwood.bivalentinsttest_self_inst",
+
     resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
     auto_gen_config: true,
 }
@@ -53,6 +56,10 @@
         "truth",
     ],
     resource_apk: "RavenwoodBivalentInstTestTarget",
+
+    package_name: "com.android.ravenwood.bivalentinst_target_app",
+    inst_package_name: "com.android.ravenwood.bivalentinsttest_nonself_inst",
+
     inst_resource_apk: "RavenwoodBivalentInstTest_nonself_inst_device",
     auto_gen_config: true,
 }
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
index 92d43d7..db252d8 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -19,8 +19,6 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,11 +37,6 @@
     private static final String TEST_PACKAGE_NAME =
             "com.android.ravenwood.bivalentinsttest_nonself_inst";
 
-    @Config
-    public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
-            .setPackageName(TEST_PACKAGE_NAME)
-            .setTargetPackageName(TARGET_PACKAGE_NAME)
-            .build();
 
     private static Instrumentation sInstrumentation;
     private static Context sTestContext;
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
index 2f35923..94b1861 100644
--- a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -19,8 +19,6 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -40,13 +38,6 @@
     private static final String TEST_PACKAGE_NAME =
             "com.android.ravenwood.bivalentinsttest_self_inst";
 
-    @Config
-    public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
-            .setPackageName(TEST_PACKAGE_NAME)
-            .setTargetPackageName(TARGET_PACKAGE_NAME)
-            .build();
-
-
     private static Instrumentation sInstrumentation;
     private static Context sTestContext;
     private static Context sTargetContext;
diff --git a/ravenwood/tests/bivalenttest/Android.bp b/ravenwood/tests/bivalenttest/Android.bp
index 40e6672..ac545df 100644
--- a/ravenwood/tests/bivalenttest/Android.bp
+++ b/ravenwood/tests/bivalenttest/Android.bp
@@ -84,6 +84,8 @@
 android_ravenwood_test {
     name: "RavenwoodBivalentTest",
     defaults: ["ravenwood-bivalent-defaults"],
+    target_sdk_version: "34",
+    package_name: "com.android.ravenwoodtest.bivalenttest",
     auto_gen_config: true,
 }
 
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
index a5a16c1..306c2b39 100644
--- a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodConfigTest.java
@@ -20,8 +20,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
 
-import android.platform.test.ravenwood.RavenwoodConfig;
-
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -33,13 +31,7 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class RavenwoodConfigTest {
-    private static final String PACKAGE_NAME = "com.test";
-
-    @RavenwoodConfig.Config
-    public static RavenwoodConfig sConfig =
-            new RavenwoodConfig.Builder()
-                    .setPackageName(PACKAGE_NAME)
-                    .build();
+    private static final String PACKAGE_NAME = "com.android.ravenwoodtest.bivalenttest";
 
     @Test
     public void testConfig() {
diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
index a95760d..882c91c 100644
--- a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
+++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/compat/RavenwoodCompatFrameworkTest.kt
@@ -16,8 +16,6 @@
 package com.android.ravenwoodtest.bivalenttest.compat
 
 import android.app.compat.CompatChanges
-import android.os.Build
-import android.platform.test.ravenwood.RavenwoodConfig
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.internal.ravenwood.RavenwoodEnvironment.CompatIdsForTest
 import org.junit.Assert
@@ -26,14 +24,6 @@
 
 @RunWith(AndroidJUnit4::class)
 class RavenwoodCompatFrameworkTest {
-    companion object {
-        @JvmField // Expose as a raw field, not as a property.
-        @RavenwoodConfig.Config
-        val config = RavenwoodConfig.Builder()
-            .setTargetSdkLevel(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-            .build()
-    }
-
     @Test
     fun testEnabled() {
         Assert.assertTrue(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_1))
@@ -53,4 +43,4 @@
     fun testEnabledAfterUForUApps() {
         Assert.assertFalse(CompatChanges.isChangeEnabled(CompatIdsForTest.TEST_COMPAT_ID_4))
     }
-}
\ No newline at end of file
+}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
index 02d1073..f94b98b 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
@@ -24,6 +24,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
@@ -32,6 +33,10 @@
 
 /**
  * Test for @Config field extraction and validation.
+ *
+ * TODO(b/377765941) Most of the tests here will be obsolete and deleted with b/377765941, but
+ * some of the tests may need to be re-implemented one way or another. (e.g. the package name
+ * test.) Until that happens, we'll keep all tests here but add an {@code @Ignore} instead.
  */
 @NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner.
 public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase {
@@ -59,6 +64,7 @@
     testRunFinished: 1,0,0,0
     """)
     // CHECKSTYLE:ON
+    @Ignore // Package name is no longer set via config.
     public static class ConfigInBaseClassTest extends ConfigInBaseClass {
         @Test
         public void test() {
@@ -83,6 +89,7 @@
     testRunFinished: 1,0,0,0
     """)
     // CHECKSTYLE:ON
+    @Ignore // Package name is no longer set via config.
     public static class ConfigOverridingTest extends ConfigInBaseClass {
         static String PACKAGE_NAME_OVERRIDE = "com.ConfigOverridingTest";
 
@@ -376,6 +383,7 @@
     testRunFinished: 1,0,0,0
     """)
     // CHECKSTYLE:ON
+    @Ignore // Package name is no longer set via config.
     public static class RuleInBaseClassSuccessTest extends RuleInBaseClass {
 
         @Test
@@ -437,6 +445,7 @@
     testRunFinished: 1,1,0,0
     """)
     // CHECKSTYLE:ON
+    @Ignore // Package name is no longer set via config.
     public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
 
         @Test
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
index f7a2198..0e3d053 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerTestBase.java
@@ -25,6 +25,8 @@
 
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
+
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.Description;
 import org.junit.runner.JUnitCore;
@@ -103,6 +105,7 @@
         var thisClass = this.getClass();
         var ret = Arrays.stream(thisClass.getNestMembers())
                 .filter((c) -> c.getAnnotation(Expected.class) != null)
+                .filter((c) -> c.getAnnotation(Ignore.class) == null)
                 .toArray(Class[]::new);
 
         assertThat(ret.length).isGreaterThan(0);
diff --git a/ravenwood/tests/runtime-test/Android.bp b/ravenwood/tests/runtime-test/Android.bp
index 0c0df1f..c352003 100644
--- a/ravenwood/tests/runtime-test/Android.bp
+++ b/ravenwood/tests/runtime-test/Android.bp
@@ -9,7 +9,7 @@
 
 android_ravenwood_test {
     name: "RavenwoodRuntimeTest",
-
+    target_sdk_version: "34",
     libs: [
         "ravenwood-helper-runtime",
     ],
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 827e3ef..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;
@@ -2548,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);
 
@@ -2568,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 e59bb42..4f632c9 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -353,7 +353,10 @@
     private static void addAutofillableIds(@NonNull ViewNode node,
             @NonNull ArrayList<AutofillId> ids, boolean autofillableOnly) {
         if (!autofillableOnly || node.getAutofillType() != View.AUTOFILL_TYPE_NONE) {
-            ids.add(node.getAutofillId());
+            AutofillId id = node.getAutofillId();
+            if (id != null) {
+                ids.add(id);
+            }
         }
         final int size = node.getChildCount();
         for (int i = 0; i < size; i++) {
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/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
new file mode 100644
index 0000000..5e4bab15
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2017 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.backup;
+
+import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ApplicationThreadConstants;
+import android.app.IActivityManager;
+import android.app.IBackupAgent;
+import android.app.backup.BackupAnnotations;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.backup.internal.LifecycleOperationStorage;
+
+import java.util.Set;
+
+/**
+ * Handles the lifecycle of {@link IBackupAgent}s that the {@link UserBackupManagerService}
+ * communicates with.
+ *
+ * <p>There can only be one agent that's connected to at a time.
+ *
+ * <p>There should be only one instance of this class per {@link UserBackupManagerService}.
+ */
+public class BackupAgentConnectionManager {
+
+    /**
+     * 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 android.content.pm.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;
+
+    // The thread performing the sequence of queued backups binds to each app's agent
+    // in succession.  Bind notifications are asynchronously delivered through the
+    // Activity Manager; use this lock object to signal when a requested binding has
+    // completed.
+    private final Object mAgentConnectLock = new Object();
+    private IBackupAgent mConnectedAgent;
+    private volatile boolean mConnecting;
+    private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>();
+    private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>();
+
+    private final IActivityManager mActivityManager;
+    private final ActivityManagerInternal mActivityManagerInternal;
+    private final LifecycleOperationStorage mOperationStorage;
+    private final PackageManager mPackageManager;
+    private final UserBackupManagerService mUserBackupManagerService;
+    private final int mUserId;
+    private final String mUserIdMsg;
+
+    BackupAgentConnectionManager(LifecycleOperationStorage operationStorage,
+            PackageManager packageManager, UserBackupManagerService userBackupManagerService,
+            int userId) {
+        mActivityManager = ActivityManager.getService();
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mOperationStorage = operationStorage;
+        mPackageManager = packageManager;
+        mUserBackupManagerService = userBackupManagerService;
+        mUserId = userId;
+        mUserIdMsg = "[UserID:" + userId + "] ";
+    }
+
+    /**
+     * Fires off a backup agent, blocking until it attaches (and ActivityManager will call
+     * {@link #agentConnected(String, IBinder)}) or until this operation times out.
+     *
+     * @param mode a {@code BACKUP_MODE} from {@link android.app.ApplicationThreadConstants}.
+     */
+    @Nullable
+    public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
+            @BackupAnnotations.BackupDestination int backupDestination) {
+        IBackupAgent agent = null;
+        synchronized (mAgentConnectLock) {
+            mConnecting = true;
+            mConnectedAgent = null;
+            boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode,
+                    app.packageName);
+            try {
+                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
+                        backupDestination, useRestrictedMode)) {
+                    Slog.d(TAG, mUserIdMsg + "awaiting agent for " + app);
+
+                    // success; wait for the agent to arrive
+                    // only wait 10 seconds for the bind to happen
+                    long timeoutMark = System.currentTimeMillis() + 10 * 1000;
+                    while (mConnecting && mConnectedAgent == null && (System.currentTimeMillis()
+                            < timeoutMark)) {
+                        try {
+                            mAgentConnectLock.wait(5000);
+                        } catch (InterruptedException e) {
+                            // just bail
+                            Slog.w(TAG, mUserIdMsg + "Interrupted: " + e);
+                            mConnecting = false;
+                            mConnectedAgent = null;
+                        }
+                    }
+
+                    // if we timed out with no connect, abort and move on
+                    if (mConnecting) {
+                        Slog.w(TAG, mUserIdMsg + "Timeout waiting for agent " + app);
+                        mConnectedAgent = null;
+                    }
+                    Slog.i(TAG, mUserIdMsg + "got agent " + mConnectedAgent);
+                    agent = mConnectedAgent;
+                }
+            } catch (RemoteException e) {
+                // can't happen - ActivityManager is local
+            }
+        }
+        if (agent == null) {
+            mActivityManagerInternal.clearPendingBackup(mUserId);
+        }
+        return agent;
+    }
+
+    /**
+     * Tell the ActivityManager that we are done with the {@link IBackupAgent} of this {@code app}.
+     * It will tell the app to destroy the agent.
+     */
+    public void unbindAgent(ApplicationInfo app) {
+        try {
+            mActivityManager.unbindBackupAgent(app);
+        } catch (RemoteException e) {
+            // Can't happen - activity manager is local
+        }
+    }
+
+    /**
+     * Callback: a requested backup agent has been instantiated. This should only be called from
+     * the
+     * {@link ActivityManager} when it's telling us that an agent is ready after a call to
+     * {@link #bindToAgentSynchronous(ApplicationInfo, int, int)}.
+     */
+    public void agentConnected(String packageName, IBinder agentBinder) {
+        synchronized (mAgentConnectLock) {
+            if (getCallingUid() == android.os.Process.SYSTEM_UID) {
+                Slog.d(TAG,
+                        mUserIdMsg + "agentConnected pkg=" + packageName + " agent=" + agentBinder);
+                mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
+                mConnecting = false;
+            } else {
+                Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
+                        + " claiming agent connected");
+            }
+            mAgentConnectLock.notifyAll();
+        }
+    }
+
+    /**
+     * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed
+     * to come up in the first place, the agentBinder argument will be {@code null}. This should
+     * only be called from the {@link ActivityManager}.
+     */
+    public void agentDisconnected(String packageName) {
+        synchronized (mAgentConnectLock) {
+            if (getCallingUid() == Process.SYSTEM_UID) {
+                mConnectedAgent = null;
+                mConnecting = false;
+            } else {
+                Slog.w(TAG, mUserIdMsg + "Non-system process uid=" + getCallingUid()
+                        + " claiming agent disconnected");
+            }
+            Slog.w(TAG, mUserIdMsg + "agentDisconnected: the backup agent for " + packageName
+                    + " died: cancel current operations");
+
+            // Offload operation cancellation off the main thread as the cancellation callbacks
+            // might call out to BackupTransport. Other operations started on the same package
+            // before the cancellation callback has executed will also be cancelled by the callback.
+            Runnable cancellationRunnable = () -> {
+                // handleCancel() causes the PerformFullTransportBackupTask to go on to
+                // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
+                // that the package being backed up doesn't get stuck in restricted mode until the
+                // backup time-out elapses.
+                for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
+                    if (MORE_DEBUG) {
+                        Slog.d(TAG,
+                                mUserIdMsg + "agentDisconnected: will handleCancel(all) for token:"
+                                        + Integer.toHexString(token));
+                    }
+                    mUserBackupManagerService.handleCancel(token, true /* cancelAll */);
+                }
+            };
+            getThreadForCancellation(cancellationRunnable).start();
+
+            mAgentConnectLock.notifyAll();
+        }
+    }
+
+    /**
+     * 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;
+    }
+
+    @VisibleForTesting
+    Thread getThreadForCancellation(Runnable operation) {
+        return new Thread(operation, /* operationName */ "agent-disconnected");
+    }
+
+    @VisibleForTesting
+    int getCallingUid() {
+        return Binder.getCallingUid();
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5f0071d..3f6ede9 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -658,7 +658,8 @@
                 getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
 
         if (userBackupManagerService != null) {
-            userBackupManagerService.agentConnected(packageName, agentBinder);
+            userBackupManagerService.getBackupAgentConnectionManager().agentConnected(packageName,
+                    agentBinder);
         }
     }
 
@@ -683,7 +684,8 @@
                 getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
 
         if (userBackupManagerService != null) {
-            userBackupManagerService.agentDisconnected(packageName);
+            userBackupManagerService.getBackupAgentConnectionManager().agentDisconnected(
+                    packageName);
         }
     }
 
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index f5d6836..136bacd 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -146,7 +146,8 @@
 
     private IBackupAgent bindToAgent(ApplicationInfo targetApp) {
         try {
-            return mBackupManagerService.bindToAgentSynchronous(targetApp,
+            return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
+                    targetApp,
                     ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
                     BackupAnnotations.BackupDestination.CLOUD);
         } catch (SecurityException e) {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 466d477..e085f6e 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -44,7 +44,6 @@
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
-import android.app.IBackupAgent;
 import android.app.PendingIntent;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupAnnotations;
@@ -79,7 +78,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
@@ -302,8 +300,6 @@
     // CPU on bring-up and increase time-to-UI.
     private static final long INITIALIZATION_DELAY_MILLIS = 3000;
 
-    // Timeout interval for deciding that a bind has taken too long.
-    private static final long BIND_TIMEOUT_INTERVAL = 10 * 1000;
     // Timeout interval for deciding that a clear-data has taken too long.
     private static final long CLEAR_DATA_TIMEOUT_INTERVAL = 30 * 1000;
 
@@ -354,17 +350,7 @@
 
     // locking around the pending-backup management
     private final Object mQueueLock = new Object();
-
     private final UserBackupPreferences mBackupPreferences;
-
-    // The thread performing the sequence of queued backups binds to each app's agent
-    // in succession.  Bind notifications are asynchronously delivered through the
-    // Activity Manager; use this lock object to signal when a requested binding has
-    // completed.
-    private final Object mAgentConnectLock = new Object();
-    private IBackupAgent mConnectedAgent;
-    private volatile boolean mConnecting;
-
     private volatile boolean mBackupRunning;
     private volatile long mLastBackupPass;
 
@@ -394,6 +380,7 @@
 
     private ActiveRestoreSession mActiveRestoreSession;
 
+    private final BackupAgentConnectionManager mBackupAgentConnectionManager;
     private final LifecycleOperationStorage mOperationStorage;
 
     private final Random mTokenGenerator = new Random();
@@ -523,17 +510,22 @@
     @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;
         mRegisterTransportsRequestedTime = 0;
         mPackageManager = packageManager;
         mOperationStorage = operationStorage;
+        mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
+                mPackageManager, this, mUserId);
         mTransportManager = transportManager;
         mFullBackupQueue = new ArrayList<>();
         mBackupHandler = backupHandler;
         mConstants = backupManagerConstants;
+        mActivityManager = activityManager;
+        mActivityManagerInternal = activityManagerInternal;
 
         mBaseStateDir = null;
         mDataDir = null;
@@ -543,13 +535,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;
     }
@@ -582,6 +572,8 @@
         mAgentTimeoutParameters.start();
 
         mOperationStorage = new LifecycleOperationStorage(mUserId);
+        mBackupAgentConnectionManager = new BackupAgentConnectionManager(mOperationStorage,
+                mPackageManager, this, mUserId);
 
         Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null");
         mBackupHandler = new BackupHandler(this, mOperationStorage, userBackupThread);
@@ -1643,65 +1635,6 @@
         }
     }
 
-    /** Fires off a backup agent, blocking until it attaches or times out. */
-    @Nullable
-    public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
-            @BackupDestination int backupDestination) {
-        IBackupAgent agent = null;
-        synchronized (mAgentConnectLock) {
-            mConnecting = true;
-            mConnectedAgent = null;
-            try {
-                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
-                        backupDestination)) {
-                    Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));
-
-                    // success; wait for the agent to arrive
-                    // only wait 10 seconds for the bind to happen
-                    long timeoutMark = System.currentTimeMillis() + BIND_TIMEOUT_INTERVAL;
-                    while (mConnecting && mConnectedAgent == null
-                            && (System.currentTimeMillis() < timeoutMark)) {
-                        try {
-                            mAgentConnectLock.wait(5000);
-                        } catch (InterruptedException e) {
-                            // just bail
-                            Slog.w(TAG, addUserIdToLogMessage(mUserId, "Interrupted: " + e));
-                            mConnecting = false;
-                            mConnectedAgent = null;
-                        }
-                    }
-
-                    // if we timed out with no connect, abort and move on
-                    if (mConnecting) {
-                        Slog.w(
-                                TAG,
-                                addUserIdToLogMessage(mUserId, "Timeout waiting for agent " + app));
-                        mConnectedAgent = null;
-                    }
-                    if (DEBUG) {
-                        Slog.i(TAG, addUserIdToLogMessage(mUserId, "got agent " + mConnectedAgent));
-                    }
-                    agent = mConnectedAgent;
-                }
-            } catch (RemoteException e) {
-                // can't happen - ActivityManager is local
-            }
-        }
-        if (agent == null) {
-            mActivityManagerInternal.clearPendingBackup(mUserId);
-        }
-        return agent;
-    }
-
-    /** Unbind from a backup agent. */
-    public void unbindAgent(ApplicationInfo app) {
-        try {
-            mActivityManager.unbindBackupAgent(app);
-        } catch (RemoteException e) {
-            // Can't happen - activity manager is local
-        }
-    }
-
     /**
      * Clear an application's data after a failed restore, blocking until the operation completes or
      * times out.
@@ -2474,10 +2407,6 @@
         AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
     }
 
-    // *****************************
-    // NEW UNIFIED RESTORE IMPLEMENTATION
-    // *****************************
-
     /** Schedule a backup pass for {@code packageName}. */
     public void dataChangedImpl(String packageName) {
         HashSet<String> targets = dataChangedTargets(packageName);
@@ -3794,83 +3723,6 @@
     }
 
     /**
-     * Callback: a requested backup agent has been instantiated. This should only be called from the
-     * {@link ActivityManager}.
-     */
-    public void agentConnected(String packageName, IBinder agentBinder) {
-        synchronized (mAgentConnectLock) {
-            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
-                Slog.d(
-                        TAG,
-                        addUserIdToLogMessage(
-                                mUserId,
-                                "agentConnected pkg=" + packageName + " agent=" + agentBinder));
-                mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
-                mConnecting = false;
-            } else {
-                Slog.w(
-                        TAG,
-                        addUserIdToLogMessage(
-                                mUserId,
-                                "Non-system process uid="
-                                        + Binder.getCallingUid()
-                                        + " claiming agent connected"));
-            }
-            mAgentConnectLock.notifyAll();
-        }
-    }
-
-    /**
-     * Callback: a backup agent has failed to come up, or has unexpectedly quit. If the agent failed
-     * to come up in the first place, the agentBinder argument will be {@code null}. This should
-     * only be called from the {@link ActivityManager}.
-     */
-    public void agentDisconnected(String packageName) {
-        synchronized (mAgentConnectLock) {
-            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
-                mConnectedAgent = null;
-                mConnecting = false;
-            } else {
-                Slog.w(
-                        TAG,
-                        addUserIdToLogMessage(
-                                mUserId,
-                                "Non-system process uid="
-                                        + Binder.getCallingUid()
-                                        + " claiming agent disconnected"));
-            }
-            Slog.w(TAG, "agentDisconnected: the backup agent for " + packageName
-                    + " died: cancel current operations");
-
-            // Offload operation cancellation off the main thread as the cancellation callbacks
-            // might call out to BackupTransport. Other operations started on the same package
-            // before the cancellation callback has executed will also be cancelled by the callback.
-            Runnable cancellationRunnable = () -> {
-                // handleCancel() causes the PerformFullTransportBackupTask to go on to
-                // tearDownAgentAndKill: that will unbindBackupAgent in the Activity Manager, so
-                // that the package being backed up doesn't get stuck in restricted mode until the
-                // backup time-out elapses.
-                for (int token : mOperationStorage.operationTokensForPackage(packageName)) {
-                    if (MORE_DEBUG) {
-                        Slog.d(TAG, "agentDisconnected: will handleCancel(all) for token:"
-                                + Integer.toHexString(token));
-                    }
-                    handleCancel(token, true /* cancelAll */);
-                }
-            };
-            getThreadForAsyncOperation(/* operationName */ "agent-disconnected",
-                    cancellationRunnable).start();
-
-            mAgentConnectLock.notifyAll();
-        }
-    }
-
-    @VisibleForTesting
-    Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
-        return new Thread(operation, operationName);
-    }
-
-    /**
      * An application being installed will need a restore pass, then the {@link PackageManager} will
      * need to be told when the restore is finished.
      */
@@ -4417,4 +4269,8 @@
     public IBackupManager getBackupManagerBinder() {
         return mBackupManagerBinder;
     }
+
+    public BackupAgentConnectionManager getBackupAgentConnectionManager() {
+        return mBackupAgentConnectionManager;
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 1271206..b98cb10 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -314,7 +314,7 @@
                 Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
             }
             mAgent =
-                    backupManagerService.bindToAgentSynchronous(
+                    backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
                             mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL,
                             mBackupEligibilityRules.getBackupDestination());
         }
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..65730c9 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,10 @@
                 mUserBackupManagerService.scheduleNextFullBackupJob(backoff);
             }
 
+            // Clear this to avoid using the memory until reboot.
+            mUserBackupManagerService
+                    .getBackupAgentConnectionManager().clearNoRestrictedModePackages();
+
             Slog.i(TAG, "Full data backup pass finished.");
             mUserBackupManagerService.getWakelock().release();
         }
@@ -722,6 +733,22 @@
         }
     }
 
+    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.getBackupAgentConnectionManager().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/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 3a6e1ca..82232a6 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -741,7 +741,7 @@
         final IBackupAgent agent;
         try {
             agent =
-                    mBackupManagerService.bindToAgentSynchronous(
+                    mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
                             packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL,
                             mBackupEligibilityRules.getBackupDestination());
             if (agent == null) {
@@ -1302,7 +1302,8 @@
 
         // For PM metadata (for which applicationInfo is null) there is no agent-bound state.
         if (mCurrentPackage.applicationInfo != null) {
-            mBackupManagerService.unbindAgent(mCurrentPackage.applicationInfo);
+            mBackupManagerService.getBackupAgentConnectionManager().unbindAgent(
+                    mCurrentPackage.applicationInfo);
         }
         mAgent = null;
     }
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 2d99c96..b59e860 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -410,11 +410,7 @@
 
                             // All set; now set up the IPC and launch the agent
                             setUpPipes();
-                            mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp,
-                                    FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
-                                            ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
-                                            : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
-                                    mBackupEligibilityRules.getBackupDestination());
+                            mAgent = bindToAgent(info);
                             mAgentPackage = pkg;
                         } catch (IOException | NameNotFoundException e) {
                             // fall through to error handling
@@ -805,15 +801,12 @@
         return packages.contains(packageName);
     }
 
-    void sendOnRestorePackage(String name) {
-        if (mObserver != null) {
-            try {
-                // TODO: use a more user-friendly name string
-                mObserver.onRestorePackage(name);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "full restore observer went away: restorePackage");
-                mObserver = null;
-            }
-        }
+    private IBackupAgent bindToAgent(FileMetadata info) {
+        return mBackupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
+                mTargetApp,
+                FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
+                        ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
+                        : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
+                mBackupEligibilityRules.getBackupDestination());
     }
 }
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..e5c7e5c 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");
@@ -809,7 +814,7 @@
 
         // Good to go!  Set up and bind the agent...
         mAgent =
-                backupManagerService.bindToAgentSynchronous(
+                backupManagerService.getBackupAgentConnectionManager().bindToAgentSynchronous(
                         mCurrentPackage.applicationInfo,
                         ApplicationThreadConstants.BACKUP_MODE_RESTORE,
                         mBackupEligibilityRules.getBackupDestination());
@@ -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.getBackupAgentConnectionManager().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,21 @@
 
         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.getBackupAgentConnectionManager().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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fa22862..e57b009 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -65,6 +65,7 @@
 import android.telephony.CellSignalStrengthNr;
 import android.telephony.CellSignalStrengthTdscdma;
 import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.DisconnectCause;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.LocationAccessPolicy;
@@ -76,6 +77,7 @@
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.PreciseDisconnectCause;
 import android.telephony.Rlog;
+import android.telephony.SecurityAlgorithmUpdate;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -590,7 +592,9 @@
                 || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
                 || events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED)
                 || events.contains(TelephonyCallback
-                        .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED);
+                        .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED)
+                || events.contains(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED)
+                || events.contains(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED);
     }
 
     private static final int MSG_USER_SWITCHED = 1;
@@ -897,7 +901,6 @@
         mIsSatelliteEnabled = new AtomicBoolean();
         mWasSatelliteEnabledNotified = new AtomicBoolean();
 
-
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -3825,7 +3828,6 @@
         }
     }
 
-
     /**
      * Notify external listeners that carrier roaming non-terrestrial network
      * signal strength changed.
@@ -3835,7 +3837,7 @@
     public void notifyCarrierRoamingNtnSignalStrengthChanged(int subId,
             @NonNull NtnSignalStrength ntnSignalStrength) {
         if (!checkNotifyPermission("notifyCarrierRoamingNtnSignalStrengthChanged")) {
-            log("nnotifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required "
+            log("notifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required "
                     + "permissions.");
             return;
         }
@@ -3863,6 +3865,98 @@
         }
     }
 
+    /**
+     * Notify that the radio security algorithms have changed.
+     *
+     * @param phoneId the phone id.
+     * @param subId the subId.
+     * @param update the security algorithm update.
+     */
+    public void notifySecurityAlgorithmsChanged(int phoneId, int subId,
+            SecurityAlgorithmUpdate update) {
+        if (!Flags.securityAlgorithmsUpdateIndications()) {
+            log("Not available due to securityAlgorithmsUpdateIndications() flag");
+            return;
+        }
+        if (!checkNotifyPermission("notifySecurityAlgorithmChanged()")) {
+            return;
+        }
+
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                if (update == null) {
+                    loge("SecurityAlgorithmUpdate is null, subId=" + subId
+                            + ", phoneId=" + phoneId);
+                    // Listeners shouldn't be updated for null updates.
+                    return;
+                }
+
+                for (Record r : mRecords) {
+                    if (r.matchTelephonyCallbackEvent(
+                            TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED)
+                            && idMatch(r, subId, phoneId)) {
+                        try {
+                            if (VDBG) {
+                                log("notifySecurityAlgorithmsChanged: securityAlgorithmUpdate= "
+                                        + update);
+                            }
+                            r.callback.onSecurityAlgorithmsChanged(update);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
+    /**
+     * Notify of a cellular identifier disclosure.
+     *
+     * @param phoneId the phone id.
+     * @param subId the subId.
+     * @param disclosure the cellular identifier disclosure.
+     */
+    public void notifyCellularIdentifierDisclosedChanged(int phoneId, int subId,
+            @NonNull CellularIdentifierDisclosure disclosure) {
+        if (!Flags.cellularIdentifierDisclosureIndications()) {
+            log("Not available due to cellularIdentifierDisclosureIndications() flag");
+            return;
+        }
+        if (!checkNotifyPermission("notifyCellularIdentifierDisclosedChanged()")) {
+            return;
+        }
+
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                if (disclosure == null) {
+                    loge("CellularIdentifierDisclosure is null, subId=" + subId
+                            + ", phoneId=" + phoneId);
+                    // Listeners shouldn't be updated for null disclosures.
+                    return;
+                }
+
+                for (Record r : mRecords) {
+                    if (r.matchTelephonyCallbackEvent(
+                            TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED)
+                            && idMatch(r, subId, phoneId)) {
+                        try {
+                            if (VDBG) {
+                                log("notifyCellularIdentifierDisclosedChanged: disclosure= "
+                                        + disclosure);
+                            }
+                            r.callback.onCellularIdentifierDisclosedChanged(disclosure);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @NeverCompile // Avoid size overhead of debugging code.
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dfddc08..e166807 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;
@@ -4493,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
                     }
                 });
             }
@@ -4673,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();
@@ -13499,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
                 }
             });
         }
@@ -14011,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
@@ -14096,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)
@@ -14122,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;
@@ -14221,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) {
@@ -18013,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);
         }
 
@@ -19088,8 +19070,13 @@
      */
     @Override
     public boolean enableFgsNotificationRateLimit(boolean enable) {
-        enforceCallingPermission(permission.WRITE_DEVICE_CONFIG,
-                "enableFgsNotificationRateLimit");
+        if (android.security.Flags.protectDeviceConfigFlags()) {
+            enforceCallingHasAtLeastOnePermission("enableFgsNotificationRateLimit",
+                    permission.WRITE_DEVICE_CONFIG, permission.WRITE_ALLOWLISTED_DEVICE_CONFIG);
+        } else {
+            enforceCallingPermission(permission.WRITE_DEVICE_CONFIG,
+                    "enableFgsNotificationRateLimit");
+        }
         synchronized (this) {
             return mServices.enableFgsNotificationRateLimitLocked(enable);
         }
@@ -19353,4 +19340,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/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 3913d2f..961022b 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -634,12 +634,20 @@
         }
 
         final ApplicationStartInfo info = new ApplicationStartInfo(raw);
+        int uid = raw.getRealUid();
 
-        AppStartInfoContainer container = mData.get(raw.getPackageName(), raw.getRealUid());
+        // Isolated process starts won't be reasonably accessible if stored by their uid, don't
+        // store them.
+        if (com.android.server.am.Flags.appStartInfoIsolatedProcess()
+                && UserHandle.isIsolated(uid)) {
+            return null;
+        }
+
+        AppStartInfoContainer container = mData.get(raw.getPackageName(), uid);
         if (container == null) {
             container = new AppStartInfoContainer(mAppStartInfoHistoryListSize);
-            container.mUid = info.getRealUid();
-            mData.put(raw.getPackageName(), raw.getRealUid(), container);
+            container.mUid = uid;
+            mData.put(raw.getPackageName(), uid, container);
         }
         container.addStartInfoLocked(info);
 
@@ -1010,6 +1018,17 @@
                             new AppStartInfoContainer(mAppStartInfoHistoryListSize);
                     int uid = container.readFromProto(proto, AppsStartInfoProto.Package.USERS,
                             pkgName);
+
+                    // If the isolated process flag is enabled and the uid is that of an isolated
+                    // process, then break early so that the container will not be added to mData.
+                    // This is expected only as a one time mitigation, records added after this flag
+                    // is enabled should always return false for isIsolated and thereby always
+                    // continue on.
+                    if (com.android.server.am.Flags.appStartInfoIsolatedProcess()
+                            && UserHandle.isIsolated(uid)) {
+                        break;
+                    }
+
                     synchronized (mLock) {
                         mData.put(pkgName, uid, container);
                     }
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/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index e20c46c..a32d3cb 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
@@ -56,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, ApplicationInfo applicationInfo, PlatformCompat platformCompat) {
+            boolean _exported, ApplicationInfo _applicationInfo, PlatformCompat platformCompat) {
         super(_filter);
         receiverList = _receiverList;
         packageName = _packageName;
@@ -72,6 +74,7 @@
         instantApp = _instantApp;
         visibleToInstantApp = _visibleToInstantApp;
         exported = _exported;
+        applicationInfo = _applicationInfo;
         initialPriority = getPriority();
         setPriority(calculateAdjustedPriority(owningUid, initialPriority,
                 applicationInfo, platformCompat));
@@ -87,6 +90,10 @@
         return null;
     }
 
+    public @NonNull ApplicationInfo getApplicationInfo() {
+        return applicationInfo;
+    }
+
     @NeverCompile
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index e8ce173..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;
 
@@ -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/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 711b163..6d247d2 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -260,3 +260,23 @@
     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
+    }
+}
+
+flag {
+    name: "app_start_info_isolated_process"
+    namespace: "system_performance"
+    description: "Adjust handling of isolated process records to be discarded."
+    bug: "374032823"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 5e74d67..06c586f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2876,7 +2876,8 @@
     }
 
     @Override
-    public int checkOperationForDevice(int code, int uid, String packageName, int virtualDeviceId) {
+    public int checkOperationForDevice(int code, int uid, String packageName,
+            @Nullable String attributionTag, int virtualDeviceId) {
         if (Binder.getCallingPid() != Process.myPid()
                 && Flags.appopAccessTrackingLoggingEnabled()) {
             FrameworkStatsLog.write(
@@ -2884,7 +2885,7 @@
                     APP_OP_NOTE_OP_OR_CHECK_OP_BINDER_API_CALLED__BINDER_API__CHECK_OPERATION,
                     false);
         }
-        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, null,
+        return mCheckOpsDelegateDispatcher.checkOperation(code, uid, packageName, attributionTag,
                 virtualDeviceId, false /*raw*/);
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6ba3569..6e6bf80 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:"
@@ -14159,10 +14166,10 @@
      * Update player event
      * @param piid Player id to update
      * @param event The new player event
-     * @param eventValue The value associated with this event
+     * @param eventValues The values associated with this event
      */
-    public void playerEvent(int piid, int event, int eventValue) {
-        mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid());
+    public void playerEvent(int piid, int event, int[] eventValues) {
+        mPlaybackMonitor.playerEvent(piid, event, eventValues, Binder.getCallingUid());
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b63b07f..a62ac82 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;
@@ -364,10 +365,11 @@
      * @param eventValue The value associated with this event
      * @param binderUid Calling binder uid
      */
-    public void playerEvent(int piid, int event, int eventValue, int binderUid) {
+    public void playerEvent(int piid, int event, int[] eventValues, int binderUid) {
         if (DEBUG) {
-            Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)",
-                    piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue));
+            Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValues=%d)",
+                    piid, AudioPlaybackConfiguration.playerStateToString(event),
+                    Arrays.toString(eventValues)));
         }
         boolean change;
         synchronized(mPlayerLock) {
@@ -381,13 +383,13 @@
                 // do not log nor dispatch events for "ignored" players other than the release
                 return;
             }
-            sEventLogger.enqueue(new PlayerEvent(piid, event, eventValue));
+            sEventLogger.enqueue(new PlayerEvent(piid, event, eventValues));
 
             if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) {
                 if (portToPiidSimplification()) {
-                    mPiidToPortId.put(piid, eventValue);
+                    mPiidToPortId.put(piid, eventValues[0]);
                 } else {
-                    mPortIdToPiid.put(eventValue, piid);
+                    mPortIdToPiid.put(eventValues[0], piid);
                 }
                 return;
             } else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
@@ -408,7 +410,7 @@
             if (checkConfigurationCaller(piid, apc, binderUid)) {
                 //TODO add generation counter to only update to the latest state
                 checkVolumeForPrivilegedAlarm(apc, event);
-                change = apc.handleStateEvent(event, eventValue);
+                change = apc.handleStateEvent(event, eventValues);
             } else {
                 Log.e(TAG, "Error handling event " + event);
                 change = false;
@@ -444,7 +446,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));
         }
 
@@ -516,7 +518,7 @@
                 mMutedPlayersAwaitingConnection.remove(Integer.valueOf(piid));
                 checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
                 change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
-                        AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+                        AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
 
                 if (portToPiidSimplification()) {
                     mPiidToPortId.delete(piid);
@@ -1335,12 +1337,12 @@
         // only keeping the player interface ID as it uniquely identifies the player in the event
         final int mPlayerIId;
         final int mEvent;
-        final int mEventValue;
+        final int[] mEventValues;
 
-        PlayerEvent(int piid, int event, int eventValue) {
+        PlayerEvent(int piid, int event, int[] eventValues) {
             mPlayerIId = piid;
             mEvent = event;
-            mEventValue = eventValue;
+            mEventValues = eventValues;
         }
 
         @Override
@@ -1352,35 +1354,40 @@
             switch (mEvent) {
                 case AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID:
                     return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:"
-                            + mEventValue + " mapped to player piid:" + mPlayerIId;
+                            + Arrays.toString(mEventValues) + " mapped to player piid:"
+                            + mPlayerIId;
                 case AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID:
-                    if (mEventValue != 0) {
-                        builder.append(" deviceId:").append(mEventValue);
+                    if ((mEventValues.length > 0) && (mEventValues[0] != 0)) {
+                        builder.append(" deviceIds:").append(Arrays.toString(mEventValues));
                     }
                     return builder.toString();
                 case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED:
                     builder.append(" source:");
-                    if (mEventValue <= 0) {
+                    int eventValue = mEventValues[0];
+                    if (eventValue <= 0) {
                         builder.append("none ");
                     } else {
-                        if ((mEventValue & MUTED_BY_MASTER) != 0) {
+                        if ((eventValue & MUTED_BY_MASTER) != 0) {
                             builder.append("masterMute ");
                         }
-                        if ((mEventValue & MUTED_BY_STREAM_VOLUME) != 0) {
+                        if ((eventValue & MUTED_BY_STREAM_VOLUME) != 0) {
                             builder.append("streamVolume ");
                         }
-                        if ((mEventValue & MUTED_BY_STREAM_MUTED) != 0) {
+                        if ((eventValue & MUTED_BY_STREAM_MUTED) != 0) {
                             builder.append("streamMute ");
                         }
-                        if ((mEventValue & MUTED_BY_APP_OPS) != 0) {
+                        if ((eventValue & MUTED_BY_APP_OPS) != 0) {
                             builder.append("appOps ");
                         }
-                        if ((mEventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
+                        if ((eventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
                             builder.append("clientVolume ");
                         }
-                        if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
+                        if ((eventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
                             builder.append("volumeShaper ");
                         }
+                        if ((eventValue & MUTED_BY_PORT_VOLUME) != 0) {
+                            builder.append("portVolume ");
+                        }
                     }
                     return builder.toString();
                 default:
@@ -1728,8 +1735,11 @@
                         synchronized (mPlayerLock) {
                             int piid = msg.arg1;
 
+
+                            int[] eventValues = new int[1];
+                            eventValues[0] = eventValue;
                             sEventLogger.enqueue(
-                                    new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue));
+                                    new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValues));
 
                             final AudioPlaybackConfiguration apc = mPlayers.get(piid);
                             if (apc == null || !apc.handleMutedEvent(eventValue)) {
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/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 82d5d4d..e8786be 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -677,10 +677,11 @@
      * Start the timeout for the watchdog.
      */
     public void startWatchdog() {
-        if (mCurrentOperation == null) {
+        final BiometricSchedulerOperation operation = mCurrentOperation;
+        if (operation == null) {
+            Slog.e(TAG, "Current operation is null,no need to start watchdog");
             return;
         }
-        final BiometricSchedulerOperation operation = mCurrentOperation;
         mHandler.postDelayed(() -> {
             if (operation == mCurrentOperation && !operation.isFinished()) {
                 Counter.logIncrement("biometric.value_scheduler_watchdog_triggered_count");
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 abb756b..62fcccf 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -5283,6 +5283,23 @@
         }
 
         @Override
+        public void setScreenBrightnessOverrideFromWindowManager(
+                SparseArray<DisplayBrightnessOverrideRequest> brightnessOverrides) {
+            SparseArray<DisplayPowerController> dpcs = new SparseArray<>();
+            synchronized (mSyncRoot) {
+                for (int i = 0; i < mDisplayPowerControllers.size(); i++) {
+                    dpcs.put(mDisplayPowerControllers.keyAt(i),
+                            mDisplayPowerControllers.valueAt(i));
+                }
+            }
+            for (int i = 0; i < dpcs.size(); ++i) {
+                final int displayId = dpcs.keyAt(i);
+                final DisplayPowerController dpc = dpcs.valueAt(i);
+                dpc.setBrightnessOverrideRequest(brightnessOverrides.get(displayId));
+            }
+        }
+
+        @Override
         public boolean requestPowerState(int groupId, DisplayPowerRequest request,
                 boolean waitForNegativeProximity) {
             synchronized (mSyncRoot) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c90dfbf..2948ae4 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -42,6 +42,7 @@
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -170,6 +171,7 @@
     private static final int MSG_OFFLOADING_SCREEN_ON_UNBLOCKED = 18;
     private static final int MSG_SET_STYLUS_BEING_USED = 19;
     private static final int MSG_SET_STYLUS_USE_ENDED = 20;
+    private static final int MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE = 21;
 
     private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500;
 
@@ -850,6 +852,12 @@
         }
     }
 
+    public void setBrightnessOverrideRequest(
+            DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+        Message msg = mHandler.obtainMessage(MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE, request);
+        mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
+    }
+
     public void setDisplayOffloadSession(DisplayOffloadSession session) {
         if (session == mDisplayOffloadSession) {
             return;
@@ -3100,6 +3108,13 @@
                     updatePowerState();
                     break;
 
+                case MSG_SET_WINDOW_MANAGER_BRIGHTNESS_OVERRIDE:
+                    if (mDisplayBrightnessController.updateWindowManagerBrightnessOverride(
+                            (DisplayManagerInternal.DisplayBrightnessOverrideRequest) msg.obj)) {
+                        updatePowerState();
+                    }
+                    break;
+
                 case MSG_STOP:
                     cleanupHandlerThreadAfterStop();
                     break;
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 5b12dfb..35f6fd0 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -180,6 +180,20 @@
     }
 
     /**
+     * Updates the brightness override from WindowManager.
+     *
+     * @param request The request to override the brightness
+     * @return whether this request will result in a change of the brightness
+     */
+    public boolean updateWindowManagerBrightnessOverride(
+            DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+        synchronized (mLock) {
+            return mDisplayBrightnessStrategySelector.getOverrideBrightnessStrategy()
+                    .updateWindowManagerBrightnessOverride(request);
+        }
+    }
+
+    /**
      * Sets the brightness to follow
      */
     public void setBrightnessToFollow(float brightnessToFollow, boolean slowChange) {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 60c1b8f..a0ad49d 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -180,8 +180,10 @@
             displayBrightnessStrategy = mFollowerBrightnessStrategy;
         } else if (displayPowerRequest.boostScreenBrightness) {
             displayBrightnessStrategy = mBoostBrightnessStrategy;
-        } else if (BrightnessUtils
-                .isValidBrightnessValue(displayPowerRequest.screenBrightnessOverride)) {
+        } else if (BrightnessUtils.isValidBrightnessValue(
+                displayPowerRequest.screenBrightnessOverride)
+                || BrightnessUtils.isValidBrightnessValue(
+                        mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())) {
             displayBrightnessStrategy = mOverrideBrightnessStrategy;
         } else if (BrightnessUtils.isValidBrightnessValue(
                 mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) {
@@ -256,6 +258,10 @@
         return mAutoBrightnessFallbackStrategy;
     }
 
+    public OverrideBrightnessStrategy getOverrideBrightnessStrategy() {
+        return mOverrideBrightnessStrategy;
+    }
+
     /**
      * Dumps the state of this class.
      */
diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
index 3fc15d1..649f9da 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java
@@ -16,10 +16,13 @@
 
 package com.android.server.display.brightness.strategy;
 
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManager;
 
 import com.android.server.display.DisplayBrightnessState;
 import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
 import com.android.server.display.brightness.StrategyExecutionRequest;
 import com.android.server.display.brightness.StrategySelectionNotifyRequest;
 
@@ -29,6 +32,10 @@
  * Manages the brightness of the display when the system brightness is overridden
  */
 public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy {
+
+    private float mWindowManagerBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+    private CharSequence mWindowManagerBrightnessOverrideTag = null;
+
     @Override
     public DisplayBrightnessState updateBrightness(
             StrategyExecutionRequest strategyExecutionRequest) {
@@ -36,9 +43,18 @@
         // the brightness
         DisplayPowerRequest dpr = strategyExecutionRequest.getDisplayPowerRequest();
         BrightnessReason reason = new BrightnessReason(BrightnessReason.REASON_OVERRIDE);
-        reason.setTag(dpr.screenBrightnessOverrideTag);
+
+        float brightness = dpr.screenBrightnessOverride;
+        if (BrightnessUtils.isValidBrightnessValue(dpr.screenBrightnessOverride)) {
+            brightness = dpr.screenBrightnessOverride;
+            reason.setTag(dpr.screenBrightnessOverrideTag);
+        } else if (BrightnessUtils.isValidBrightnessValue(mWindowManagerBrightnessOverride)) {
+            brightness = mWindowManagerBrightnessOverride;
+            reason.setTag(mWindowManagerBrightnessOverrideTag);
+        }
+
         return new DisplayBrightnessState.Builder()
-                .setBrightness(dpr.screenBrightnessOverride)
+                .setBrightness(brightness)
                 .setBrightnessReason(reason)
                 .setDisplayBrightnessStrategyName(getName())
                 .build();
@@ -50,7 +66,12 @@
     }
 
     @Override
-    public void dump(PrintWriter writer) {}
+    public void dump(PrintWriter writer) {
+        writer.println("OverrideBrightnessStrategy:");
+        writer.println("  mWindowManagerBrightnessOverride=" + mWindowManagerBrightnessOverride);
+        writer.println("  mWindowManagerBrightnessOverrideTag="
+                + mWindowManagerBrightnessOverrideTag);
+    }
 
     @Override
     public void strategySelectionPostProcessor(
@@ -58,6 +79,37 @@
         // DO NOTHING
     }
 
+    /**
+     * Updates the brightness override from WindowManager.
+     *
+     * @param request The request to override the brightness
+     * @return whether this request will result in a change of the brightness
+     */
+    public boolean updateWindowManagerBrightnessOverride(
+            DisplayManagerInternal.DisplayBrightnessOverrideRequest request) {
+        float newBrightness = request == null
+                ? PowerManager.BRIGHTNESS_INVALID_FLOAT : request.brightness;
+        mWindowManagerBrightnessOverrideTag = request == null ? null : request.tag;
+
+        if (floatEquals(newBrightness, mWindowManagerBrightnessOverride)) {
+            return false;
+        }
+
+        mWindowManagerBrightnessOverride = newBrightness;
+        return true;
+    }
+
+    /**
+     * Returns the current brightness override from WindowManager.
+     */
+    public float getWindowManagerBrightnessOverride() {
+        return mWindowManagerBrightnessOverride;
+    }
+
+    private boolean floatEquals(float f1, float f2) {
+        return f1 == f2 || (Float.isNaN(f1) && Float.isNaN(f2));
+    }
+
     @Override
     public int getReason() {
         return BrightnessReason.REASON_OVERRIDE;
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/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 586d594..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"
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 82449ce..e5b077d 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();
 
@@ -2937,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;
@@ -3032,6 +3031,11 @@
         return mKeyGestureController.getAppLaunchBookmarks();
     }
 
+    @Override
+    public void resetLockedModifierState() {
+        mNative.resetLockedModifierState();
+    }
+
     private void handleCurrentUserChanged(@UserIdInt int userId) {
         mCurrentUserId = userId;
         mKeyGestureController.setCurrentUserId(userId);
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 8903c27..728e440 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -98,6 +98,8 @@
 
     void toggleCapsLock(int deviceId);
 
+    void resetLockedModifierState();
+
     void displayRemoved(int displayId);
 
     void setInputDispatchMode(boolean enabled, boolean frozen);
@@ -370,6 +372,9 @@
         public native void toggleCapsLock(int deviceId);
 
         @Override
+        public native void resetLockedModifierState();
+
+        @Override
         public native void displayRemoved(int displayId);
 
         @Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d8483f7..b7af9a4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1310,7 +1310,7 @@
         // Do not reset the default (current) IME when it is a 3rd-party IME
         String selectedMethodId = bindingController.getSelectedMethodId();
         final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
-        if (selectedMethodId != null
+        if (selectedMethodId != null && settings.getMethodMap().get(selectedMethodId) != null
                 && !settings.getMethodMap().get(selectedMethodId).isSystem()) {
             return;
         }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index 0fdd0ae..5248a05 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -237,15 +237,16 @@
 
         if (message.isBroadcastMessage()) {
             if (message.isReliable()) {
-                Log.e(TAG, "Received reliable broadcast message from " + message.getNanoAppId());
+                Log.e(TAG, "Received reliable broadcast message from 0x"
+                        + Long.toHexString(message.getNanoAppId()));
                 return ErrorCode.PERMANENT_ERROR;
             }
 
             // Broadcast messages shouldn't be sent with any permissions tagged per CHRE API
             // requirements.
             if (!messagePermissions.isEmpty()) {
-                Log.e(TAG, "Received broadcast message with permissions from "
-                        + message.getNanoAppId());
+                Log.e(TAG, "Received broadcast message with permissions from 0x"
+                        + Long.toHexString(message.getNanoAppId()));
                 return ErrorCode.PERMANENT_ERROR;
             }
 
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..7c9d9c5 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,
@@ -322,14 +326,22 @@
         }
 
         if (Flags.offloadApi()) {
-            mHubInfoRegistry = new HubInfoRegistry(mContextHubWrapper);
-            Log.i(TAG, "Enabling generic offload API");
+            HubInfoRegistry registry;
+            try {
+                registry = new HubInfoRegistry(mContextHubWrapper);
+                Log.i(TAG, "Enabling generic offload API");
+            } catch (UnsupportedOperationException e) {
+                registry = null;
+                Log.w(TAG, "Generic offload API not supported, disabling");
+            }
+            mHubInfoRegistry = registry;
         } else {
             mHubInfoRegistry = null;
             Log.i(TAG, "Disabling generic offload API");
         }
 
         initDefaultClientMap();
+        initEndpointCallback();
 
         initLocationSettingNotifications();
         initWifiSettingNotifications();
@@ -508,6 +520,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 +763,36 @@
         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 List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) {
+        super.findEndpointsWithService_enforcePermission();
+        if (mHubInfoRegistry == null) {
+            return Collections.emptyList();
+        }
+        return mHubInfoRegistry.findEndpointsWithService(serviceDescriptor);
+    }
+
+    @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..d2b2331 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,161 @@
 
 package com.android.server.location.contexthub;
 
+import android.hardware.contexthub.HubEndpointInfo;
+import android.hardware.contexthub.HubServiceInfo;
 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;
+    }
+
+    /**
+     * Return a list of {@link HubEndpointInfo} that represents endpoints with the matching service.
+     */
+    public List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) {
+        List<HubEndpointInfo> searchResult = new ArrayList<>();
+        synchronized (mLock) {
+            for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) {
+                for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) {
+                    if (serviceDescriptor.equals(serviceInfo.getServiceDescriptor())) {
+                        searchResult.add(endpointInfo);
+                    }
+                }
+            }
+        }
+        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/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 436acba..df5ecf8 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,14 +1002,13 @@
         }
     }
 
-    @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)
         // before starting capture, but after requesting consent.
-        final long mDefaultTimeoutMs = Duration.ofMinutes(5).toMillis();
+        final long mDefaultTimeoutMillis = Duration.ofMinutes(5).toMillis();
         // The creation timestamp in milliseconds, measured by {@link SystemClock#uptimeMillis}.
-        private final long mCreateTimeMs;
+        private final long mCreateTimeMillis;
         public final int uid;
         public final String packageName;
         public final UserHandle userHandle;
@@ -1092,7 +1017,7 @@
         private final int mType;
         // Values for tracking token validity.
         // Timeout value to compare creation time against.
-        private final long mTimeoutMs = mDefaultTimeoutMs;
+        private final long mTimeoutMillis = mDefaultTimeoutMillis;
         private final int mDisplayId;
 
         private IMediaProjectionCallback mCallback;
@@ -1123,7 +1048,7 @@
             userHandle = new UserHandle(UserHandle.getUserId(uid));
             mTargetSdkVersion = targetSdkVersion;
             mIsPrivileged = isPrivileged;
-            mCreateTimeMs = mClock.uptimeMillis();
+            mCreateTimeMillis = mClock.uptimeMillis();
             mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
                     MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
             mDisplayId = displayId;
@@ -1284,7 +1209,7 @@
                     }
                 }
                 Slog.d(TAG, "Content Recording: handling stopping this projection token"
-                        + " createTime= " + mCreateTimeMs
+                        + " createTime= " + mCreateTimeMillis
                         + " countStarts= " + mCountStarts);
                 stopProjectionLocked(this);
                 mToken.unlinkToDeath(mDeathEater, 0);
@@ -1347,13 +1272,17 @@
             return mDisplayId;
         }
 
+        long getCreateTimeMillis() {
+            return mCreateTimeMillis;
+        }
+
         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
         @Override
         public boolean isValid() {
             isValid_enforcePermission();
             synchronized (mLock) {
-                final long curMs = mClock.uptimeMillis();
-                final boolean hasTimedOut = curMs - mCreateTimeMs > mTimeoutMs;
+                final long curMillis = mClock.uptimeMillis();
+                final boolean hasTimedOut = curMillis - mCreateTimeMillis > mTimeoutMillis;
                 final boolean virtualDisplayCreated = mVirtualDisplayId != INVALID_DISPLAY;
                 final boolean isValid =
                         !hasTimedOut && (mCountStarts <= 1) && !virtualDisplayCreated;
@@ -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 c5c8a5e..00bab8a 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -25,11 +25,11 @@
 import android.media.quality.IMediaQualityManager;
 import android.media.quality.IPictureProfileCallback;
 import android.media.quality.ISoundProfileCallback;
-import android.media.quality.MediaQualityContract.PictureQuality;
+import android.media.quality.MediaQualityContract;
 import android.media.quality.ParamCapability;
 import android.media.quality.PictureProfile;
 import android.media.quality.SoundProfile;
-import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.util.Log;
 
 import com.android.server.SystemService;
@@ -74,10 +74,10 @@
             SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
             ContentValues values = new ContentValues();
-            values.put(PictureQuality.PARAMETER_TYPE, pp.getProfileType());
-            values.put(PictureQuality.PARAMETER_NAME, pp.getName());
-            values.put(PictureQuality.PARAMETER_PACKAGE, pp.getPackageName());
-            values.put(PictureQuality.PARAMETER_INPUT_ID, pp.getInputId());
+            values.put(MediaQualityContract.BaseParameters.PARAMETER_TYPE, pp.getProfileType());
+            values.put(MediaQualityContract.BaseParameters.PARAMETER_NAME, pp.getName());
+            values.put(MediaQualityContract.BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
+            values.put(MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
             values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
 
             // id is auto-generated by SQLite upon successful insertion of row
@@ -98,8 +98,8 @@
         public PictureProfile getPictureProfile(int type, String name) {
             SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
 
-            String selection = PictureQuality.PARAMETER_TYPE + " = ? AND "
-                    + PictureQuality.PARAMETER_NAME + " = ?";
+            String selection = MediaQualityContract.BaseParameters.PARAMETER_TYPE + " = ? AND "
+                    + MediaQualityContract.BaseParameters.PARAMETER_NAME + " = ?";
             String[] selectionArguments = {Integer.toString(type), name};
 
             try (
@@ -127,7 +127,7 @@
             }
         }
 
-        private String bundleToJson(Bundle bundle) {
+        private String bundleToJson(PersistableBundle bundle) {
             JSONObject jsonObject = new JSONObject();
             if (bundle == null) {
                 return jsonObject.toString();
@@ -142,9 +142,9 @@
             return jsonObject.toString();
         }
 
-        private Bundle jsonToBundle(String jsonString) {
+        private PersistableBundle jsonToBundle(String jsonString) {
             JSONObject jsonObject = null;
-            Bundle bundle = new Bundle();
+            PersistableBundle bundle = new PersistableBundle();
 
             try {
                 jsonObject = new JSONObject(jsonString);
@@ -175,26 +175,26 @@
 
         private String[] getAllPictureProfileColumns() {
             return new String[]{
-                    PictureQuality.PARAMETER_ID,
-                    PictureQuality.PARAMETER_TYPE,
-                    PictureQuality.PARAMETER_NAME,
-                    PictureQuality.PARAMETER_INPUT_ID,
-                    PictureQuality.PARAMETER_PACKAGE,
+                    MediaQualityContract.BaseParameters.PARAMETER_ID,
+                    MediaQualityContract.BaseParameters.PARAMETER_TYPE,
+                    MediaQualityContract.BaseParameters.PARAMETER_NAME,
+                    MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID,
+                    MediaQualityContract.BaseParameters.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 returnId = cursor.getString(cursor.getColumnIndexOrThrow(
+                    MediaQualityContract.BaseParameters.PARAMETER_ID));
+            int type = cursor.getInt(cursor.getColumnIndexOrThrow(
+                    MediaQualityContract.BaseParameters.PARAMETER_TYPE));
+            String name = cursor.getString(cursor.getColumnIndexOrThrow(
+                    MediaQualityContract.BaseParameters.PARAMETER_NAME));
+            String inputId = cursor.getString(cursor.getColumnIndexOrThrow(
+                    MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID));
+            String packageName = cursor.getString(cursor.getColumnIndexOrThrow(
+                    MediaQualityContract.BaseParameters.PARAMETER_PACKAGE));
             String settings = cursor.getString(
                     cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
             return new PictureProfile(returnId, type, name, inputId,
@@ -203,7 +203,7 @@
 
         @Override
         public List<PictureProfile> getPictureProfilesByPackage(String packageName) {
-            String selection = PictureQuality.PARAMETER_PACKAGE + " = ?";
+            String selection = MediaQualityContract.BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {packageName};
             return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
                     selectionArguments);
@@ -216,7 +216,7 @@
 
         @Override
         public List<String> getPictureProfilePackageNames() {
-            String [] column = {PictureQuality.PARAMETER_NAME};
+            String [] column = {MediaQualityContract.BaseParameters.PARAMETER_NAME};
             List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
                     null, null);
             List<String> packageNames = new ArrayList<>();
@@ -262,7 +262,7 @@
             // TODO: implement
         }
         @Override
-        public SoundProfile getSoundProfileById(String id) {
+        public SoundProfile getSoundProfile(int type, String id) {
             return null;
         }
         @Override
@@ -313,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/DefaultDeviceEffectsApplier.java b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
index 925ba17..3e96afe 100644
--- a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
+++ b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java
@@ -39,9 +39,11 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.Keep;
 
 /** Default implementation for {@link DeviceEffectsApplier}. */
-class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
+@Keep
+public class DefaultDeviceEffectsApplier implements DeviceEffectsApplier {
     private static final String TAG = "DeviceEffectsApplier";
     private static final String SUPPRESS_AMBIENT_DISPLAY_TOKEN =
             "DefaultDeviceEffectsApplier:SuppressAmbientDisplay";
@@ -63,10 +65,10 @@
     @GuardedBy("mRegisterReceiverLock")
     private boolean mIsScreenOffReceiverRegistered;
 
-    private ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build();
+    protected ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build();
     private boolean mPendingNightMode;
 
-    DefaultDeviceEffectsApplier(Context context) {
+    public DefaultDeviceEffectsApplier(Context context) {
         mContext = context;
         mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
@@ -79,58 +81,71 @@
 
     @Override
     public void apply(ZenDeviceEffects effects, @ConfigOrigin int origin) {
-        Binder.withCleanCallingIdentity(() -> {
-            if (mLastAppliedEffects.shouldSuppressAmbientDisplay()
-                    != effects.shouldSuppressAmbientDisplay()) {
-                try {
-                    traceApplyDeviceEffect("suppressAmbientDisplay",
-                            effects.shouldSuppressAmbientDisplay());
-                    mPowerManager.suppressAmbientDisplay(SUPPRESS_AMBIENT_DISPLAY_TOKEN,
-                            effects.shouldSuppressAmbientDisplay());
-                } catch (Exception e) {
-                    Slog.e(TAG, "Could not change AOD override", e);
-                }
-            }
-
-            if (mLastAppliedEffects.shouldDisplayGrayscale() != effects.shouldDisplayGrayscale()) {
-                if (mColorDisplayManager != null) {
-                    try {
-                        traceApplyDeviceEffect("displayGrayscale",
-                                effects.shouldDisplayGrayscale());
-                        mColorDisplayManager.setSaturationLevel(
-                                effects.shouldDisplayGrayscale() ? SATURATION_LEVEL_GRAYSCALE
-                                        : SATURATION_LEVEL_FULL_COLOR);
-                    } catch (Exception e) {
-                        Slog.e(TAG, "Could not change grayscale override", e);
-                    }
-                }
-            }
-
-            if (mLastAppliedEffects.shouldDimWallpaper() != effects.shouldDimWallpaper()) {
-                if (mWallpaperManager != null) {
-                    try {
-                        traceApplyDeviceEffect("dimWallpaper", effects.shouldDimWallpaper());
-                        mWallpaperManager.setWallpaperDimAmount(
-                                effects.shouldDimWallpaper() ? WALLPAPER_DIM_AMOUNT_DIMMED
-                                        : WALLPAPER_DIM_AMOUNT_NORMAL);
-                    } catch (Exception e) {
-                        Slog.e(TAG, "Could not change wallpaper override", e);
-                    }
-                }
-            }
-
-            if (mLastAppliedEffects.shouldUseNightMode() != effects.shouldUseNightMode()) {
-                try {
-                    updateOrScheduleNightMode(effects.shouldUseNightMode(), origin);
-                } catch (Exception e) {
-                    Slog.e(TAG, "Could not change dark theme override", e);
-                }
-            }
-        });
+        Binder.withCleanCallingIdentity(
+                () -> {
+                    maybeSuppressAmbientDisplay(effects.shouldSuppressAmbientDisplay());
+                    maybeDisplayGrayscale(effects.shouldDisplayGrayscale());
+                    maybeDimWallpaper(effects.shouldDimWallpaper());
+                    maybeUseNightMode(effects.shouldUseNightMode(), origin);
+                });
 
         mLastAppliedEffects = effects;
     }
 
+    protected void maybeSuppressAmbientDisplay(boolean shouldSuppressAmbientDisplay) {
+        if (mLastAppliedEffects.shouldSuppressAmbientDisplay() != shouldSuppressAmbientDisplay) {
+            try {
+                traceApplyDeviceEffect("suppressAmbientDisplay", shouldSuppressAmbientDisplay);
+                mPowerManager.suppressAmbientDisplay(
+                        SUPPRESS_AMBIENT_DISPLAY_TOKEN, shouldSuppressAmbientDisplay);
+            } catch (Exception e) {
+                Slog.e(TAG, "Could not change AOD override", e);
+            }
+        }
+    }
+
+    protected void maybeDisplayGrayscale(boolean shouldDisplayGrayscale) {
+        if (mLastAppliedEffects.shouldDisplayGrayscale() != shouldDisplayGrayscale) {
+            if (mColorDisplayManager != null) {
+                try {
+                    traceApplyDeviceEffect("displayGrayscale", shouldDisplayGrayscale);
+                    mColorDisplayManager.setSaturationLevel(
+                            shouldDisplayGrayscale
+                                    ? SATURATION_LEVEL_GRAYSCALE
+                                    : SATURATION_LEVEL_FULL_COLOR);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Could not change grayscale override", e);
+                }
+            }
+        }
+    }
+
+    protected void maybeDimWallpaper(boolean shouldDimWallpaper) {
+        if (mLastAppliedEffects.shouldDimWallpaper() != shouldDimWallpaper) {
+            if (mWallpaperManager != null) {
+                try {
+                    traceApplyDeviceEffect("dimWallpaper", shouldDimWallpaper);
+                    mWallpaperManager.setWallpaperDimAmount(
+                            shouldDimWallpaper
+                                    ? WALLPAPER_DIM_AMOUNT_DIMMED
+                                    : WALLPAPER_DIM_AMOUNT_NORMAL);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Could not change wallpaper override", e);
+                }
+            }
+        }
+    }
+
+    protected void maybeUseNightMode(boolean shouldUseNightMode, @ConfigOrigin int origin) {
+        if (mLastAppliedEffects.shouldUseNightMode() != shouldUseNightMode) {
+            try {
+                updateOrScheduleNightMode(shouldUseNightMode, origin);
+            } catch (Exception e) {
+                Slog.e(TAG, "Could not change dark theme override", e);
+            }
+        }
+    }
+
     private void updateOrScheduleNightMode(boolean useNightMode, @ConfigOrigin int origin) {
         mPendingNightMode = useNightMode;
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index ca4f83f..81dc38a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1015,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/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index d9e7696..8168c54 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1029,12 +1029,14 @@
                 if (reconciledPackages == null) {
                     return;
                 }
-                if (Flags.improveInstallFreeze()) {
-                    prepPerformDexoptIfNeeded(reconciledPackages);
-                }
-                if (renameAndUpdatePaths(requests)
-                        && commitInstallPackages(reconciledPackages)) {
-                    success = true;
+                if (renameAndUpdatePaths(requests)) {
+                    // rename before dexopt because art will encoded the path in the odex/vdex file
+                    if (Flags.improveInstallFreeze()) {
+                        prepPerformDexoptIfNeeded(reconciledPackages);
+                    }
+                    if (commitInstallPackages(reconciledPackages)) {
+                        success = true;
+                    }
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2c09423..286333c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -96,7 +96,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IInterface;
-import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -2667,6 +2666,7 @@
                 }
                 final String[] packagesNullExtras = packagesWithoutExtras.toArray(
                         new String[packagesWithoutExtras.size()]);
+
                 final int n = mListeners.beginBroadcast();
                 try {
                     for (int i = 0; i < n; i++) {
@@ -2852,7 +2852,7 @@
         class SecureSettingsObserver extends ContentObserver {
 
             SecureSettingsObserver() {
-                super(new Handler(Looper.getMainLooper()));
+                super(mCallbackHandler);
             }
 
             @Override
@@ -2866,32 +2866,29 @@
                     if (privateProfile.getIdentifier() == UserHandle.USER_NULL) {
                         return;
                     }
-
                     final int n = mListeners.beginBroadcast();
                     try {
                         for (int i = 0; i < n; i++) {
-                            final IOnAppsChangedListener listener =
-                                    mListeners.getBroadcastItem(i);
+                            final IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                             final BroadcastCookie cookie =
-                                    (BroadcastCookie) mListeners.getBroadcastCookie(
-                                            i);
+                                    (BroadcastCookie) mListeners.getBroadcastCookie(i);
                             if (!isEnabledProfileOf(cookie, privateProfile,
                                     "onSecureSettingsChange")) {
                                 Log.d(TAG, "onSecureSettingsChange: Skipping - profile not enabled"
                                         + " or not accessible for package=" + cookie.packageName
                                         + ", packageUid=" + cookie.callingUid);
-                            } else {
-                                try {
-                                    Log.d(TAG,
-                                            "onUserConfigChanged: triggering onUserConfigChanged");
-                                    listener.onUserConfigChanged(
-                                            mUserManagerInternal.getLauncherUserInfo(
-                                                    privateProfile.getIdentifier()));
-                                } catch (RemoteException re) {
-                                    Slog.d(TAG, "onUserConfigChanged: Callback failed ", re);
-                                }
+                                continue;
+                            }
+                            try {
+                                Log.d(TAG, "onUserConfigChanged: triggering onUserConfigChanged");
+                                listener.onUserConfigChanged(
+                                        mUserManagerInternal.getLauncherUserInfo(
+                                                privateProfile.getIdentifier()));
+                            } catch (RemoteException re) {
+                                Slog.d(TAG, "onUserConfigChanged: Callback failed ", re);
                             }
                         }
+
                     } finally {
                         mListeners.finishBroadcast();
                     }
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/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..c573293 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -625,14 +625,6 @@
     boolean mIsFaceDown = false;
     private long mLastFlipTime = 0L;
 
-    // The screen brightness setting override from the window manager
-    // to allow the current foreground activity to override the brightness.
-    private float mScreenBrightnessOverrideFromWindowManager =
-            PowerManager.BRIGHTNESS_INVALID_FLOAT;
-
-    // Tag identifying the window/activity that requested the brightness override.
-    private CharSequence mScreenBrightnessOverrideFromWmTag = null;
-
     // The window manager has determined the user to be inactive via other means.
     // Set this to false to disable.
     private boolean mUserInactiveOverrideFromWindowManager;
@@ -2332,6 +2324,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 +2423,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);
@@ -3662,9 +3655,7 @@
                     // Keep the brightness steady during boot. This requires the
                     // bootloader brightness and the default brightness to be identical.
                     screenBrightnessOverride = mScreenBrightnessDefault;
-                } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
-                    screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
-                    overrideTag = mScreenBrightnessOverrideFromWmTag;
+                    overrideTag = "boot";
                 } else {
                     screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
                 }
@@ -4448,19 +4439,6 @@
         }
     }
 
-    private void setScreenBrightnessOverrideFromWindowManagerInternal(
-            float brightness, CharSequence tag) {
-        synchronized (mLock) {
-            if (!BrightnessSynchronizer.floatEquals(mScreenBrightnessOverrideFromWindowManager,
-                    brightness)) {
-                mScreenBrightnessOverrideFromWindowManager = brightness;
-                mScreenBrightnessOverrideFromWmTag = tag;
-                mDirty |= DIRTY_SETTINGS;
-                updatePowerStateLocked();
-            }
-        }
-    }
-
     private void setUserInactiveOverrideFromWindowManagerInternal() {
         synchronized (mLock) {
             mUserInactiveOverrideFromWindowManager = true;
@@ -4799,10 +4777,6 @@
                     + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
                     + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
             pw.println("  mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
-            pw.println("  mScreenBrightnessOverrideFromWindowManager="
-                    + mScreenBrightnessOverrideFromWindowManager);
-            pw.println("  mScreenBrightnessOverrideFromWmTag="
-                    + mScreenBrightnessOverrideFromWmTag);
             pw.println("  mUserActivityTimeoutOverrideFromWindowManager="
                     + mUserActivityTimeoutOverrideFromWindowManager);
             pw.println("  mUserInactiveOverrideFromWindowManager="
@@ -5192,10 +5166,6 @@
 
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto
-                            .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
-                    mScreenBrightnessOverrideFromWindowManager);
-            proto.write(
-                    PowerServiceSettingsAndConfigurationDumpProto
                             .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
                     mUserActivityTimeoutOverrideFromWindowManager);
             proto.write(
@@ -7135,17 +7105,6 @@
     @VisibleForTesting
     final class LocalService extends PowerManagerInternal {
         @Override
-        public void setScreenBrightnessOverrideFromWindowManager(
-                float screenBrightness, CharSequence tag) {
-            if (screenBrightness < PowerManager.BRIGHTNESS_MIN
-                    || screenBrightness > PowerManager.BRIGHTNESS_MAX) {
-                screenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-                tag = null;
-            }
-            setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness, tag);
-        }
-
-        @Override
         public void setDozeOverrideFromDreamManager(
                 int screenState, int reason, float screenBrightnessFloat, int screenBrightnessInt,
                 boolean useNormalBrightnessForDoze) {
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 81%
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..6798a61 100644
--- a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java
+++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.server.security.adaptiveauthentication;
+package com.android.server.security.authenticationpolicy;
+
+import static android.Manifest.permission.MANAGE_SECURE_LOCK_DEVICE;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST;
 
+import android.annotation.EnforcePermission;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -32,9 +35,14 @@
 import android.hardware.biometrics.events.AuthenticationSucceededInfo;
 import android.os.Build;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.security.authenticationpolicy.IAuthenticationPolicyService;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -55,8 +63,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
@@ -74,16 +82,17 @@
     private final KeyguardManager mKeyguardManager;
     private final WindowManagerInternal mWindowManager;
     private final UserManagerInternal mUserManager;
+    private SecureLockDeviceServiceInternal mSecureLockDeviceService;
     @VisibleForTesting
     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(
@@ -94,10 +103,16 @@
         mWindowManager = Objects.requireNonNull(
                 LocalServices.getService(WindowManagerInternal.class));
         mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
+        if (android.security.Flags.secureLockdown()) {
+            mSecureLockDeviceService = Objects.requireNonNull(
+                    LocalServices.getService(SecureLockDeviceServiceInternal.class));
+        }
     }
 
     @Override
-    public void onStart() {}
+    public void onStart() {
+        publishBinderService(Context.AUTHENTICATION_POLICY_SERVICE, mService);
+    }
 
     @Override
     public void onBootPhase(int phase) {
@@ -294,4 +309,36 @@
         // next successful primary or biometric auth happens
         mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime());
     }
+
+    private final IBinder mService = new IAuthenticationPolicyService.Stub() {
+        /**
+         * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams)
+         * @param params EnableSecureLockDeviceParams for caller to supply params related
+         *               to the secure lock device request
+         * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the Secure
+         * Lock Device request
+         */
+        @Override
+        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
+        @AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus
+        public int enableSecureLockDevice(EnableSecureLockDeviceParams params) {
+            enableSecureLockDevice_enforcePermission();
+            return mSecureLockDeviceService.enableSecureLockDevice(params);
+        }
+
+        /**
+         * @see AuthenticationPolicyManager#disableSecureLockDevice(DisableSecureLockDeviceParams)
+         * @param params @DisableSecureLockDeviceParams for caller to supply params related
+         *               to the secure lock device request
+         * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the Secure
+         * Lock Device request
+         */
+        @Override
+        @EnforcePermission(MANAGE_SECURE_LOCK_DEVICE)
+        @AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus
+        public int disableSecureLockDevice(DisableSecureLockDeviceParams params) {
+            disableSecureLockDevice_enforcePermission();
+            return mSecureLockDeviceService.disableSecureLockDevice(params);
+        }
+    };
 }
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/authenticationpolicy/SecureLockDeviceService.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java
new file mode 100644
index 0000000..7b89723
--- /dev/null
+++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.security.authenticationpolicy;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+/**
+ * System service for remotely calling secure lock on the device.
+ *
+ * Callers will access this class via
+ * {@link com.android.server.security.authenticationpolicy.AuthenticationPolicyService}.
+ *
+ * @see AuthenticationPolicyService
+ * @see AuthenticationPolicyManager#enableSecureLockDevice
+ * @see AuthenticationPolicyManager#disableSecureLockDevice
+ * @hide
+ */
+public class SecureLockDeviceService extends SecureLockDeviceServiceInternal {
+    private static final String TAG = "SecureLockDeviceService";
+    private final Context mContext;
+
+    public SecureLockDeviceService(@NonNull Context context) {
+        mContext = context;
+    }
+
+    private void start() {
+        // Expose private service for system components to use.
+        LocalServices.addService(SecureLockDeviceServiceInternal.class, this);
+    }
+
+    /**
+     * @see AuthenticationPolicyManager#enableSecureLockDevice
+     * @param params EnableSecureLockDeviceParams for caller to supply params related
+     *               to the secure lock device request
+     * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the
+     * secure lock device request
+     *
+     * @hide
+     */
+    @Override
+    @EnableSecureLockDeviceRequestStatus
+    public int enableSecureLockDevice(EnableSecureLockDeviceParams params) {
+        // (1) Call into system_server to lock device, configure allowed auth types
+        // for secure lock
+        // TODO: lock device, configure allowed authentication types for device entry
+        // (2) Call into framework to configure secure lock 2FA lockscreen
+        // update, UI & string updates
+        // TODO: implement 2FA lockscreen when SceneContainerFlag.isEnabled()
+        // TODO: implement 2FA lockscreen when !SceneContainerFlag.isEnabled()
+        // (3) Call into framework to configure keyguard security updates
+        // TODO: implement security updates
+        return AuthenticationPolicyManager.ERROR_UNSUPPORTED;
+    }
+
+    /**
+     * @see AuthenticationPolicyManager#disableSecureLockDevice
+     * @param params @DisableSecureLockDeviceParams for caller to supply params related
+     *               to the secure lock device request
+     * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the
+     * secure lock device request
+     *
+     * @hide
+     */
+    @Override
+    @DisableSecureLockDeviceRequestStatus
+    public int disableSecureLockDevice(DisableSecureLockDeviceParams params) {
+        // (1) Call into system_server to reset allowed auth types
+        // TODO: reset allowed authentication types for device entry;
+        // (2) Call into framework to disable secure lock 2FA lockscreen, reset UI
+        // & string updates
+        // TODO: implement reverting to normal lockscreen when SceneContainerFlag.isEnabled()
+        // TODO: implement reverting to normal lockscreen when !SceneContainerFlag.isEnabled()
+        // (3) Call into framework to revert keyguard security updates
+        // TODO: implement reverting security updates
+        return AuthenticationPolicyManager.ERROR_UNSUPPORTED;
+    }
+
+    /**
+     * System service lifecycle.
+     */
+    public static final class Lifecycle extends SystemService {
+        private final SecureLockDeviceService mService;
+
+        public Lifecycle(@NonNull Context context) {
+            super(context);
+            mService = new SecureLockDeviceService(context);
+        }
+
+        @Override
+        public void onStart() {
+            Slog.i(TAG, "Starting SecureLockDeviceService");
+            mService.start();
+            Slog.i(TAG, "Started SecureLockDeviceService");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java
new file mode 100644
index 0000000..b903709
--- /dev/null
+++ b/services/core/java/com/android/server/security/authenticationpolicy/SecureLockDeviceServiceInternal.java
@@ -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.
+ */
+
+package com.android.server.security.authenticationpolicy;
+
+import android.security.authenticationpolicy.AuthenticationPolicyManager;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.DisableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.AuthenticationPolicyManager.EnableSecureLockDeviceRequestStatus;
+import android.security.authenticationpolicy.DisableSecureLockDeviceParams;
+import android.security.authenticationpolicy.EnableSecureLockDeviceParams;
+
+/**
+ * Local system service interface for {@link SecureLockDeviceService}.
+ *
+ * <p>No permission / argument checks will be performed inside.
+ * Callers must check the calling app permission and the calling package name.
+ *
+ * @hide
+ */
+public abstract class SecureLockDeviceServiceInternal {
+    private static final String TAG = "SecureLockDeviceServiceInternal";
+
+    /**
+     * @see AuthenticationPolicyManager#enableSecureLockDevice(EnableSecureLockDeviceParams)
+     * @param params EnableSecureLockDeviceParams for caller to supply params related
+     *               to the secure lock request
+     * @return @EnableSecureLockDeviceRequestStatus int indicating the result of the
+     * secure lock request
+     */
+    @EnableSecureLockDeviceRequestStatus
+    public abstract int enableSecureLockDevice(EnableSecureLockDeviceParams params);
+
+    /**
+     * @see AuthenticationPolicyManager#disableSecureLockDevice(DisableSecureLockDeviceParams)
+     * @param params @DisableSecureLockDeviceParams for caller to supply params related
+     *               to the secure lock device request
+     * @return @DisableSecureLockDeviceRequestStatus int indicating the result of the
+     * secure lock device request
+     */
+    @DisableSecureLockDeviceRequestStatus
+    public abstract int disableSecureLockDevice(DisableSecureLockDeviceParams params);
+}
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/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 465ac2f..887e186 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -61,6 +61,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -84,6 +85,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.infra.AndroidFuture;
+import com.android.internal.policy.IDeviceLockedStateListener;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
@@ -105,6 +107,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.IntStream;
 
 /**
  * Manages trust agents and trust listeners.
@@ -253,6 +256,10 @@
             new SparseArray<>();
     private final SparseArray<TrustableTimeoutAlarmListener>
             mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
+
+    private final RemoteCallbackList<IDeviceLockedStateListener>
+            mDeviceLockedStateListeners = new RemoteCallbackList<>();
+
     private AlarmManager mAlarmManager;
     private final Object mAlarmLock = new Object();
 
@@ -1090,6 +1097,7 @@
         if (changed) {
             notifyTrustAgentsOfDeviceLockState(userId, locked);
             notifyKeystoreOfDeviceLockState(userId, locked);
+            notifyDeviceLockedListenersForUser(userId, locked);
             // Also update the user's profiles who have unified challenge, since they
             // share the same unlocked state (see {@link #isDeviceLocked(int)})
             for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
@@ -1910,6 +1918,26 @@
             return mIsInSignificantPlace;
         }
 
+        @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+        @Override
+        public void registerDeviceLockedStateListener(IDeviceLockedStateListener listener,
+                int deviceId) {
+            super.registerDeviceLockedStateListener_enforcePermission();
+            if (deviceId != Context.DEVICE_ID_DEFAULT) {
+                // Virtual devices are considered insecure.
+                return;
+            }
+            mDeviceLockedStateListeners.register(listener,
+                    Integer.valueOf(UserHandle.getUserId(Binder.getCallingUid())));
+        }
+
+        @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+        @Override
+        public void unregisterDeviceLockedStateListener(IDeviceLockedStateListener listener) {
+            super.unregisterDeviceLockedStateListener_enforcePermission();
+            mDeviceLockedStateListeners.unregister(listener);
+        }
+
         private void enforceReportPermission() {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -2031,6 +2059,7 @@
                     }
 
                     notifyKeystoreOfDeviceLockState(userId, locked);
+                    notifyDeviceLockedListenersForUser(userId, locked);
 
                     if (locked) {
                         try {
@@ -2497,4 +2526,24 @@
             updateTrust(mUserId, 0 /* flags */);
         }
     }
+
+    private void notifyDeviceLockedListenersForUser(int userId, boolean locked) {
+        int numListeners = mDeviceLockedStateListeners.beginBroadcast();
+        try {
+            IntStream.range(0, numListeners).forEach(i -> {
+                try {
+                    Integer uid = (Integer) mDeviceLockedStateListeners.getBroadcastCookie(i);
+                    if (userId == uid.intValue()) {
+                        mDeviceLockedStateListeners.getBroadcastItem(i)
+                                .onDeviceLockedStateChanged(locked);
+                    }
+                } catch (RemoteException re) {
+                    Log.i(TAG, "Service died", re);
+                }
+            });
+
+        } finally {
+            mDeviceLockedStateListeners.finishBroadcast();
+        }
+    }
 }
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/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 1030df6..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,8 @@
                             mVibrationSettings.getRequestVibrationParamsTimeoutMs());
         }
 
-        return new VibrationStepConductor(vib, /* isInSession= */ false, mVibrationSettings,
-                mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger,
+        return new VibrationStepConductor(vib, isInSession, mVibrationSettings,
+                deviceAdapter, mVibrationScaler, mFrameworkStatsLogger,
                 requestVibrationParamsFuture, mVibrationThreadCallbacks);
     }
 
@@ -1136,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) {
@@ -1156,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:
@@ -1766,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);
@@ -1839,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
@@ -1874,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 c6e6e76..f70dec1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -630,8 +630,8 @@
     // The locusId associated with this activity, if set.
     private LocusId mLocusId;
 
-    // Whether the activity is requesting to limit the system's educational dialogs
-    public boolean mShouldLimitSystemEducationDialogs;
+    // The timestamp of the last request to show the "Open in browser" education
+    public long mRequestOpenInBrowserEducationTimestamp;
 
     // Whether the activity was launched from a bubble.
     private boolean mLaunchedFromBubble;
@@ -1623,6 +1623,11 @@
                 newParent.setResumedActivity(this, "onParentChanged");
             }
             mAppCompatController.getTransparentPolicy().start();
+            if (mState == INITIALIZING && isRestrictedFixedOrientation(info.screenOrientation)) {
+                Slog.i(TAG, "Ignoring manifest-declared fixed orientation "
+                        + ActivityInfo.screenOrientationToString(info.screenOrientation)
+                        + " of " + this + " since target sdk 36");
+            }
         }
 
         if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -3192,6 +3197,17 @@
     }
 
     /**
+     * Returns {@code true} if the orientation will be ignored for {@link #isUniversalResizeable()}.
+     */
+    private boolean isRestrictedFixedOrientation(
+            @ActivityInfo.ScreenOrientation int orientation) {
+        // Exclude "locked" because it is not explicit portrait or landscape.
+        return orientation != ActivityInfo.SCREEN_ORIENTATION_LOCKED
+                && ActivityInfo.isFixedOrientation(orientation)
+                && isUniversalResizeable();
+    }
+
+    /**
      * Returns {@code true} if the fixed orientation, aspect ratio, resizability of this activity
      * will be ignored.
      */
@@ -7326,9 +7342,8 @@
         return mLocusId;
     }
 
-    void setLimitSystemEducationDialogs(boolean limitSystemEducationDialogs) {
-        if (mShouldLimitSystemEducationDialogs == limitSystemEducationDialogs) return;
-        mShouldLimitSystemEducationDialogs = limitSystemEducationDialogs;
+    void requestOpenInBrowserEducation() {
+        mRequestOpenInBrowserEducationTimestamp = System.currentTimeMillis();
         final Task task = getTask();
         if (task != null) {
             final boolean force = isVisibleRequested() && this == task.getTopNonFinishingActivity();
@@ -8123,7 +8138,13 @@
         ProtoLog.v(WM_DEBUG_ORIENTATION,
                 "Setting requested orientation %s for %s",
                 ActivityInfo.screenOrientationToString(requestedOrientation), this);
-        setOrientation(requestedOrientation, this);
+        final int resolvedOrientation = setOrientation(requestedOrientation, this);
+        if (resolvedOrientation != requestedOrientation
+                && isRestrictedFixedOrientation(requestedOrientation)) {
+            Slog.i(TAG, "Ignoring requested fixed orientation "
+                    + ActivityInfo.screenOrientationToString(requestedOrientation)
+                    + " of " + this + " since target sdk 36");
+        }
 
         // Push the new configuration to the requested app in case where it's not pushed, e.g. when
         // the request is handled at task level with letterbox.
@@ -8214,9 +8235,7 @@
     @ActivityInfo.ScreenOrientation
     protected int getOverrideOrientation() {
         int candidateOrientation = super.getOverrideOrientation();
-        if (candidateOrientation != ActivityInfo.SCREEN_ORIENTATION_LOCKED
-                && ActivityInfo.isFixedOrientation(candidateOrientation)
-                && isUniversalResizeable()) {
+        if (isRestrictedFixedOrientation(candidateOrientation)) {
             candidateOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
         }
         return mAppCompatController.getOrientationPolicy()
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 198e14a..8ff0818 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3915,12 +3915,11 @@
     }
 
     @Override
-    public void setLimitSystemEducationDialogs(
-            IBinder appToken, boolean limitSystemEducationDialogs) {
+    public void requestOpenInBrowserEducation(IBinder appToken) {
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInRootTaskLocked(appToken);
             if (r != null) {
-                r.setLimitSystemEducationDialogs(limitSystemEducationDialogs);
+                r.requestOpenInBrowserEducation();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
index fbf9478..9754595 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -16,10 +16,9 @@
 
 package com.android.server.wm;
 
-import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
 import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -33,7 +32,6 @@
 import static com.android.server.wm.AppCompatUtils.isChangeEnabled;
 
 import android.annotation.NonNull;
-import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
 
 import com.android.server.wm.utils.OptPropFactory;
 import com.android.window.flags.Flags;
@@ -165,13 +163,13 @@
      *
      * <p>The treatment is enabled when the following conditions are met:
      * <ul>
-     * <li>Property gating the camera compatibility free-form treatment is enabled.
-     * <li>Activity isn't opted out by the device manufacturer with override.
+     * <li>Feature flag gating the camera compatibility free-form treatment is enabled.
+     * <li>Activity is opted in by the device manufacturer with override.
      * </ul>
      */
     boolean shouldApplyFreeformTreatmentForCameraCompat() {
-        return Flags.enableCameraCompatForDesktopWindowing() && !isChangeEnabled(mActivityRecord,
-                OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+        return Flags.enableCameraCompatForDesktopWindowing() && isChangeEnabled(mActivityRecord,
+                OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT);
     }
 
     boolean isOverrideOrientationOnlyForCameraEnabled() {
@@ -202,22 +200,10 @@
                 && !mActivityRecord.shouldCreateAppCompatDisplayInsets();
     }
 
-    @FreeformCameraCompatMode
-    int getFreeformCameraCompatMode() {
-        return mAppCompatCameraOverridesState.mFreeformCameraCompatMode;
-    }
-
-    void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
-        mAppCompatCameraOverridesState.mFreeformCameraCompatMode = freeformCameraCompatMode;
-    }
-
     static class AppCompatCameraOverridesState {
         // Whether activity "refresh" was requested but not finished in
         // ActivityRecord#activityResumedLocked following the camera compat force rotation in
         // DisplayRotationCompatPolicy.
         private boolean mIsRefreshRequested;
-
-        @FreeformCameraCompatMode
-        private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
     }
 }
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 2a0252a..506477f 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -38,7 +38,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.CameraCompatTaskInfo;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.view.DisplayInfo;
 import android.view.Surface;
@@ -46,7 +45,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.protolog.WmProtoLogGroups;
-import com.android.window.flags.Flags;
 
 /**
  * Policy for camera compatibility freeform treatment.
@@ -124,26 +122,6 @@
         return appBoundsChanged || displayRotationChanged;
     }
 
-    /**
-     * Whether activity is eligible for camera compatibility free-form treatment.
-     *
-     * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
-     * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
-     * provides changes to the camera and display orientation signals to match those expected on a
-     * portrait device in that orientation (for example, on a standard phone).
-     *
-     * <p>The treatment is enabled when the following conditions are met:
-     * <ul>
-     *     <li>Property gating the camera compatibility free-form treatment is enabled.
-     *     <li>Activity isn't opted out by the device manufacturer with override.
-     * </ul>
-     */
-    @VisibleForTesting
-    boolean isCameraCompatForFreeformEnabledForActivity(@NonNull ActivityRecord activity) {
-        return Flags.enableCameraCompatForDesktopWindowing() && !activity.info.isChangeEnabled(
-                ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
-    }
-
     @Override
     public void onCameraOpened(@NonNull ActivityRecord cameraActivity,
             @NonNull String cameraId) {
@@ -159,16 +137,10 @@
         }
 
         cameraActivity.recomputeConfiguration();
-        updateCameraCompatMode(cameraActivity);
         cameraActivity.getTask().dispatchTaskInfoChangedIfNeeded(/* force= */ true);
         cameraActivity.ensureActivityConfiguration(/* ignoreVisibility= */ false);
     }
 
-    private void updateCameraCompatMode(@NonNull ActivityRecord cameraActivity) {
-        cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
-                .setFreeformCameraCompatMode(getCameraCompatMode(cameraActivity));
-    }
-
     @Override
     public boolean onCameraClosed(@NonNull String cameraId) {
         // Top activity in the same task as the camera activity, or `null` if the task is
@@ -277,7 +249,8 @@
     boolean isTreatmentEnabledForActivity(@NonNull ActivityRecord activity,
             boolean checkOrientation) {
         int orientation = activity.getRequestedConfigurationOrientation();
-        return isCameraCompatForFreeformEnabledForActivity(activity)
+        return activity.mAppCompatController.getAppCompatCameraOverrides()
+                .shouldApplyFreeformTreatmentForCameraCompat()
                 && mCameraStateMonitor.isCameraRunningForActivity(activity)
                 && (!checkOrientation || orientation != ORIENTATION_UNDEFINED)
                 && activity.inFreeformWindowingMode()
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 3b24798..f40d636 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -101,8 +101,6 @@
 
     DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
         super(wms);
-        // TODO(display-area): move this up to ConfigurationContainer
-        setOverrideOrientation(SCREEN_ORIENTATION_UNSET);
         mType = type;
         mName = name;
         mFeatureId = featureId;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6707a27..c89feb4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -108,6 +108,7 @@
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayBrightnessOverrideRequest;
 import android.hardware.power.Mode;
 import android.net.Uri;
 import android.os.Binder;
@@ -185,8 +186,9 @@
     private static final long SLEEP_TRANSITION_WAIT_MILLIS = 1000L;
 
     private Object mLastWindowFreezeSource = null;
-    private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-    private CharSequence mScreenBrightnessOverrideTag;
+    // Per-display WindowManager overrides that are passed on.
+    private final SparseArray<DisplayBrightnessOverrideRequest> mDisplayBrightnessOverrides =
+            new SparseArray<>();
     private long mUserActivityTimeout = -1;
     private boolean mUpdateRotation = false;
     // Only set while traversing the default display based on its content.
@@ -775,8 +777,7 @@
                     UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
         }
 
-        mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        mScreenBrightnessOverrideTag = null;
+        mDisplayBrightnessOverrides.clear();
         mUserActivityTimeout = -1;
         mObscureApplicationContentOnSecondaryDisplays = false;
         mSustainedPerformanceModeCurrent = false;
@@ -879,18 +880,10 @@
         }
 
         if (!mWmService.mDisplayFrozen) {
-            final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN
-                    || mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX
-                    ? PowerManager.BRIGHTNESS_INVALID_FLOAT : mScreenBrightnessOverride;
-            CharSequence overrideTag = null;
-            if (brightnessOverride != PowerManager.BRIGHTNESS_INVALID_FLOAT) {
-                overrideTag = mScreenBrightnessOverrideTag;
-            }
-            int brightnessFloatAsIntBits = Float.floatToIntBits(brightnessOverride);
             // Post these on a handler such that we don't call into power manager service while
             // holding the window manager lock to avoid lock contention with power manager lock.
-            mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightnessFloatAsIntBits,
-                    0, overrideTag).sendToTarget();
+            mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, mDisplayBrightnessOverrides)
+                    .sendToTarget();
             mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
         }
 
@@ -1043,10 +1036,13 @@
         }
         if (w.isDrawn() || (w.mActivityRecord != null && w.mActivityRecord.firstWindowDrawn
                 && w.mActivityRecord.isVisibleRequested())) {
-            if (!syswin && w.mAttrs.screenBrightness >= 0
-                    && Float.isNaN(mScreenBrightnessOverride)) {
-                mScreenBrightnessOverride = w.mAttrs.screenBrightness;
-                mScreenBrightnessOverrideTag = w.getWindowTag();
+            if (!syswin && w.mAttrs.screenBrightness >= PowerManager.BRIGHTNESS_MIN
+                    && w.mAttrs.screenBrightness <= PowerManager.BRIGHTNESS_MAX
+                    && !mDisplayBrightnessOverrides.contains(w.getDisplayId())) {
+                var brightnessOverride = new DisplayBrightnessOverrideRequest();
+                brightnessOverride.brightness = w.mAttrs.screenBrightness;
+                brightnessOverride.tag = w.getWindowTag();
+                mDisplayBrightnessOverrides.put(w.getDisplayId(), brightnessOverride);
             }
 
             // This function assumes that the contents of the default display are processed first
@@ -1118,8 +1114,10 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case SET_SCREEN_BRIGHTNESS_OVERRIDE:
-                    mWmService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
-                            Float.intBitsToFloat(msg.arg1), (CharSequence) msg.obj);
+                    var brightnessOverrides =
+                            (SparseArray<DisplayBrightnessOverrideRequest>) msg.obj;
+                    mWmService.mDisplayManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+                            brightnessOverrides);
                     break;
                 case SET_USER_ACTIVITY_TIMEOUT:
                     mWmService.mPowerManagerInternal.
@@ -2856,7 +2854,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/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 dbc3b76c2..e8ae280 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3423,8 +3423,8 @@
                 ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID;
         info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays;
         info.mTopActivityLocusId = top != null ? top.getLocusId() : null;
-        info.isTopActivityLimitSystemEducationDialogs = top != null
-              ? top.mShouldLimitSystemEducationDialogs : false;
+        info.topActivityRequestOpenInBrowserEducationTimestamp = top != null
+              ? top.mRequestOpenInBrowserEducationTimestamp : 0;
         final Task parentTask = getParent() != null ? getParent().asTask() : null;
         info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer
                 ? parentTask.mTaskId
@@ -3523,6 +3523,7 @@
 
         info.capturedLink = null;
         info.capturedLinkTimestamp = 0;
+        info.topActivityRequestOpenInBrowserEducationTimestamp = 0;
     }
 
     @Nullable PictureInPictureParams getPictureInPictureParams() {
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/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 143d1b7..8562bb2 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -658,8 +658,8 @@
         }
         // Always allow WindowState to assign layers since it won't affect transition.
         return wc.asWindowState() != null || (!isPlaying()
-                // Don't assign task while collecting.
-                && !(wc.asTask() != null && isCollecting()));
+                // Don't assign task or display area layers while collecting.
+                && !((wc.asTask() != null || wc.asDisplayArea() != null) && isCollecting()));
     }
 
     @WindowConfiguration.WindowingMode
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5f92bb6..2397e03 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1676,30 +1676,36 @@
      * @param orientation the specified orientation. Needs to be one of {@link ScreenOrientation}.
      * @param requestingContainer the container which orientation request has changed. Mostly used
      *                            to ensure it gets correct configuration.
+     * @return the resolved override orientation of this window container.
      */
-    void setOrientation(@ScreenOrientation int orientation,
+    @ScreenOrientation
+    int setOrientation(@ScreenOrientation int orientation,
             @Nullable WindowContainer requestingContainer) {
         if (getOverrideOrientation() == orientation) {
-            return;
+            return orientation;
         }
-
         setOverrideOrientation(orientation);
         final WindowContainer parent = getParent();
-        if (parent != null) {
-            if (getConfiguration().orientation != getRequestedConfigurationOrientation()
-                    // Update configuration directly only if the change won't be dispatched from
-                    // ancestor. This prevents from computing intermediate configuration when the
-                    // parent also needs to be updated from the ancestor. E.g. the app requests
-                    // portrait but the task is still in landscape. While updating from display,
-                    // the task can be updated to portrait first so the configuration can be
-                    // computed in a consistent environment.
-                    && (inMultiWindowMode()
-                        || !handlesOrientationChangeFromDescendant(orientation))) {
-                // Resolve the requested orientation.
-                onConfigurationChanged(parent.getConfiguration());
-            }
-            onDescendantOrientationChanged(requestingContainer);
+        if (parent == null) {
+            return orientation;
         }
+        // The derived class can return a result that is different from the given orientation.
+        final int resolvedOrientation = getOverrideOrientation();
+        if (getConfiguration().orientation != getRequestedConfigurationOrientation(
+                false /* forDisplay */, resolvedOrientation)
+                // Update configuration directly only if the change won't be dispatched from
+                // ancestor. This prevents from computing intermediate configuration when the
+                // parent also needs to be updated from the ancestor. E.g. the app requests
+                // portrait but the task is still in landscape. While updating from display,
+                // the task can be updated to portrait first so the configuration can be
+                // computed in a consistent environment.
+                && (inMultiWindowMode()
+                        || !handlesOrientationChangeFromDescendant(orientation))) {
+            // Resolve the requested orientation.
+            onConfigurationChanged(parent.getConfiguration());
+        }
+        onDescendantOrientationChanged(requestingContainer);
+        return resolvedOrientation;
     }
 
     @ScreenOrientation
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 54b257c..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;
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 81af78e..6009848 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -182,7 +182,6 @@
 import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
 import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
-import static com.android.window.flags.Flags.secureWindowState;
 import static com.android.window.flags.Flags.surfaceTrustedOverlay;
 
 import android.annotation.CallSuper;
@@ -1187,9 +1186,7 @@
         if (surfaceTrustedOverlay() && isWindowTrustedOverlay()) {
             getPendingTransaction().setTrustedOverlay(mSurfaceControl, true);
         }
-        if (secureWindowState()) {
-            getPendingTransaction().setSecure(mSurfaceControl, isSecureLocked());
-        }
+        getPendingTransaction().setSecure(mSurfaceControl, isSecureLocked());
         // All apps should be considered as occluding when computing TrustedPresentation Thresholds.
         final boolean canOccludePresentation = !mSession.mCanAddInternalSystemWindow;
         getPendingTransaction().setCanOccludePresentation(mSurfaceControl, canOccludePresentation);
@@ -6174,18 +6171,10 @@
 
     void setSecureLocked(boolean isSecure) {
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, getName());
-        if (secureWindowState()) {
-            if (mSurfaceControl == null) {
-                return;
-            }
-            getPendingTransaction().setSecure(mSurfaceControl, isSecure);
-        } else {
-            if (mWinAnimator.mSurfaceControl == null) {
-                return;
-            }
-            getPendingTransaction().setSecure(mWinAnimator.mSurfaceControl,
-                    isSecure);
+        if (mSurfaceControl == null) {
+            return;
         }
+        getPendingTransaction().setSecure(mSurfaceControl, isSecure);
         if (mDisplayContent != null) {
             mDisplayContent.refreshImeSecureFlag(getSyncTransaction());
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a934eea..0154d95 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -49,7 +49,6 @@
 import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
 import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
 import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN;
-import static com.android.window.flags.Flags.secureWindowState;
 import static com.android.window.flags.Flags.setScPropertiesInClient;
 
 import android.content.Context;
@@ -310,12 +309,6 @@
         int flags = SurfaceControl.HIDDEN;
         final WindowManager.LayoutParams attrs = w.mAttrs;
 
-        if (!secureWindowState()) {
-            if (w.isSecureLocked()) {
-                flags |= SurfaceControl.SECURE;
-            }
-        }
-
         if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
             flags |= SurfaceControl.SKIP_SCREENSHOT;
         }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e383375..dece612 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2330,6 +2330,12 @@
     im->getInputManager()->getReader().toggleCapsLockState(deviceId);
 }
 
+static void resetLockedModifierState(JNIEnv* env, jobject nativeImplObj) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+    im->getInputManager()->getReader().resetLockedModifierState();
+}
+
 static void nativeDisplayRemoved(JNIEnv* env, jobject nativeImplObj, jint displayId) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
 
@@ -3134,6 +3140,7 @@
         {"verifyInputEvent", "(Landroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
          (void*)nativeVerifyInputEvent},
         {"toggleCapsLock", "(I)V", (void*)nativeToggleCapsLock},
+        {"resetLockedModifierState", "()V", (void*)resetLockedModifierState},
         {"displayRemoved", "(I)V", (void*)nativeDisplayRemoved},
         {"setFocusedApplication", "(ILandroid/view/InputApplicationHandle;)V",
          (void*)nativeSetFocusedApplication},
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/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 28eec5c..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
@@ -10402,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();
@@ -10437,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)
@@ -10492,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"
@@ -10530,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;
@@ -10556,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;
@@ -10928,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;
             }
@@ -11148,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) {
@@ -11467,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";
@@ -12549,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(
@@ -13965,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();
 
@@ -14585,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;
+            }
         }
     }
 
@@ -14811,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();
     }
@@ -14940,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);
@@ -15445,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) {
@@ -15473,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);
@@ -15521,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);
@@ -15814,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.",
@@ -15953,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);
         }
 
@@ -16272,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
@@ -16678,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;
                         }
@@ -16695,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,
@@ -16730,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;
             }
         }
@@ -16796,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 {
@@ -16805,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,
@@ -16817,7 +16914,7 @@
                             != PermissionChecker.PERMISSION_GRANTED) {
                         granted = PackageManager.PERMISSION_DENIED;
                     } else {
-                        granted = PackageManager.PERMISSION_GRANTED;
+                        granted = PERMISSION_GRANTED;
                     }
 
                 }
@@ -16828,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;
         }
     }
@@ -16952,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);
             }
@@ -18301,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);
@@ -19932,7 +20029,7 @@
     }
 
     private boolean isDeviceAB() {
-        return "true".equalsIgnoreCase(android.os.SystemProperties
+        return "true".equalsIgnoreCase(SystemProperties
                 .get(AB_DEVICE_KEY, ""));
     }
 
@@ -20199,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();
     }
@@ -20210,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;
     }
@@ -20956,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= */
@@ -21165,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;
@@ -21258,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(
@@ -21427,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;
@@ -21630,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");
@@ -21926,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);
@@ -22189,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(),
@@ -22225,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.");
 
@@ -22241,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.");
 
@@ -22267,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.");
 
@@ -22282,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)) {
@@ -22352,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);
     }
@@ -22360,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) {
@@ -23356,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);
     }
 
@@ -23379,8 +23613,8 @@
                 }
             }
         }
-
-        admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
+        admin = Flags.activeAdminCleanup()
+                ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId);
         return  EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin);
     }
 
@@ -23952,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,
@@ -23965,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 58e3a7d..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;
 
@@ -295,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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 19b0343..dc10dd9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -249,8 +249,10 @@
 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.authenticationpolicy.SecureLockDeviceService;
+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 +1762,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);
@@ -2651,9 +2660,15 @@
             mSystemServiceManager.startService(AuthService.class);
             t.traceEnd();
 
+            if (android.security.Flags.secureLockdown()) {
+                t.traceBegin("StartSecureLockDeviceService.Lifecycle");
+                mSystemServiceManager.startService(SecureLockDeviceService.Lifecycle.class);
+                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 +2776,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);
@@ -3053,7 +3069,10 @@
         if (com.android.ranging.flags.Flags.rangingStackEnabled()) {
             if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)
                     || context.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_WIFI_RTT)) {
+                            PackageManager.FEATURE_WIFI_RTT)
+                    || (com.android.ranging.flags.Flags.rangingCsEnabled()
+                            && context.getPackageManager().hasSystemFeature(
+                                    PackageManager.FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING))) {
                 t.traceBegin("RangingService");
                 // TODO: b/375264320 - Remove after RELEASE_RANGING_STACK is ramped to next.
                 try {
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/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index a547d0f..4e9fff2 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -31,6 +31,7 @@
 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 static org.robolectric.Shadows.shadowOf;
 import static org.testng.Assert.expectThrows;
 
@@ -96,6 +97,7 @@
     @UserIdInt private int mUserTwoId;
     @Mock private UserBackupManagerService mUserSystemService;
     @Mock private UserBackupManagerService mUserOneService;
+    @Mock private BackupAgentConnectionManager mUserOneBackupAgentConnectionManager;
     @Mock private UserBackupManagerService mUserTwoService;
 
     /** Setup */
@@ -116,6 +118,9 @@
         mShadowContext.grantPermissions(BACKUP);
         mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
 
+        when(mUserOneService.getBackupAgentConnectionManager()).thenReturn(
+                mUserOneBackupAgentConnectionManager);
+
         ShadowBinder.setCallingUid(Process.SYSTEM_UID);
     }
 
@@ -226,7 +231,7 @@
 
         backupManagerService.agentConnected(mUserOneId, TEST_PACKAGE, agentBinder);
 
-        verify(mUserOneService).agentConnected(TEST_PACKAGE, agentBinder);
+        verify(mUserOneBackupAgentConnectionManager).agentConnected(TEST_PACKAGE, agentBinder);
     }
 
     /** Test that the backup service does not route methods for non-registered users. */
@@ -239,7 +244,8 @@
 
         backupManagerService.agentConnected(mUserTwoId, TEST_PACKAGE, agentBinder);
 
-        verify(mUserOneService, never()).agentConnected(TEST_PACKAGE, agentBinder);
+        verify(mUserOneBackupAgentConnectionManager, never()).agentConnected(TEST_PACKAGE,
+                agentBinder);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 7349c14..aeb1ba9 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -107,6 +107,7 @@
 import com.android.internal.infra.AndroidFuture;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupAgentConnectionManager;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
@@ -167,7 +168,6 @@
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
 
-// TODO: Test agents timing out
 @RunWith(RobolectricTestRunner.class)
 @Config(
         shadows = {
@@ -195,6 +195,7 @@
     @Mock private IBackupManagerMonitor mMonitor;
     @Mock private OnTaskFinishedListener mListener;
     @Mock private PackageManagerInternal mPackageManagerInternal;
+    @Mock private BackupAgentConnectionManager mBackupAgentConnectionManager;
 
     private UserBackupManagerService mBackupManagerService;
     private TransportData mTransport;
@@ -257,6 +258,8 @@
         when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
         when(mBackupManagerService.getDataDir()).thenReturn(mDataDir);
         when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
+        when(mBackupManagerService.getBackupAgentConnectionManager()).thenReturn(
+                mBackupAgentConnectionManager);
 
         mBackupHandler = mBackupManagerService.getBackupHandler();
         mShadowBackupLooper = shadowOf(mBackupHandler.getLooper());
@@ -749,7 +752,8 @@
 
     /**
      * Agent unavailable means {@link
-     * UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo, int)} returns {@code null}.
+     * BackupAgentConnectionManager#bindToAgentSynchronous(ApplicationInfo, int, int)} returns
+     * {@code null}.
      *
      * @see #setUpAgent(PackageData)
      */
@@ -805,7 +809,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         doThrow(SecurityException.class)
-                .when(mBackupManagerService)
+                .when(mBackupAgentConnectionManager)
                 .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt());
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
@@ -823,7 +827,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         doThrow(SecurityException.class)
-                .when(mBackupManagerService)
+                .when(mBackupAgentConnectionManager)
                 .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt());
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
 
@@ -861,7 +865,7 @@
         runTask(task);
 
         verify(mBackupManagerService).setWorkSource(null);
-        verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+        verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
     }
 
     @Test
@@ -1097,7 +1101,7 @@
         runTask(task);
 
         verify(agentMock.agentBinder).fail(any());
-        verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+        verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
     }
 
     @Test
@@ -1418,7 +1422,8 @@
                 .isEqualTo("newState".getBytes());
         assertCleansUpFiles(mTransport, PM_PACKAGE);
         // We don't unbind PM
-        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+        verify(mBackupAgentConnectionManager, never()).unbindAgent(
+                argThat(applicationInfo(PM_PACKAGE)));
     }
 
     @Test
@@ -1439,7 +1444,8 @@
 
         runTask(task);
 
-        verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
+        verify(mBackupAgentConnectionManager, never()).unbindAgent(
+                argThat(applicationInfo(PM_PACKAGE)));
     }
 
     @Test
@@ -1642,9 +1648,10 @@
 
         runTask(task);
 
-        InOrder inOrder = inOrder(agentMock.agent, mBackupManagerService);
+        InOrder inOrder = inOrder(agentMock.agent, mBackupAgentConnectionManager);
         inOrder.verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
-        inOrder.verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
+        inOrder.verify(mBackupAgentConnectionManager).unbindAgent(
+                argThat(applicationInfo(PACKAGE_1)));
     }
 
     @Test
@@ -2634,12 +2641,12 @@
             doNothing().when(backupAgentBinder).fail(any());
             if (packageData.available) {
                 doReturn(backupAgentBinder)
-                        .when(mBackupManagerService)
+                        .when(mBackupAgentConnectionManager)
                         .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(),
                                 anyInt());
             } else {
                 doReturn(null)
-                        .when(mBackupManagerService)
+                        .when(mBackupAgentConnectionManager)
                         .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(),
                                 anyInt());
             }
@@ -2976,7 +2983,7 @@
 
     private void assertCleansUpFilesAndAgent(TransportData transport, PackageData packageData) {
         assertCleansUpFiles(transport, packageData);
-        verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(packageData)));
+        verify(mBackupAgentConnectionManager).unbindAgent(argThat(applicationInfo(packageData)));
     }
 
     private void assertCleansUpFiles(TransportData transport, PackageData packageData) {
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/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/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index e64d985..c996339 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -121,8 +121,8 @@
     private static final float PROX_SENSOR_MAX_RANGE = 5;
     private static final float DOZE_SCALE_FACTOR = 0.34f;
     private static final float DEFAULT_DOZE_BRIGHTNESS = 0.121f;
+    private static final float OVERRIDE_BRIGHTNESS = 0.567f;
 
-    private static final float BRIGHTNESS_RAMP_RATE_MINIMUM = 0.0f;
     private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f;
     private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
@@ -2438,6 +2438,36 @@
                 any(BrightnessEvent.class));
     }
 
+    @Test
+    public void brightnessOverrideInPowerRequest_enablesOverrideBrightnessStrategy() {
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.screenBrightnessOverride = OVERRIDE_BRIGHTNESS;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1);  // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(OVERRIDE_BRIGHTNESS), anyFloat(), anyFloat(),
+                eq(false));
+    }
+
+    @Test
+    public void brightnessOverrideRequest_enablesOverrideBrightnessStrategy() {
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1);  // Run updatePowerState
+
+        var dbor = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+        dbor.brightness = OVERRIDE_BRIGHTNESS;
+        mHolder.dpc.setBrightnessOverrideRequest(dbor);
+        advanceTime(1);  // Process the WM brightness override request
+
+        verify(mHolder.animator).animateTo(eq(OVERRIDE_BRIGHTNESS), anyFloat(), anyFloat(),
+                eq(false));
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index 4f875c3..49de801 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -52,6 +52,7 @@
 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
+import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
 import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
 import com.android.server.display.feature.DisplayManagerFlags;
 
@@ -155,6 +156,27 @@
     }
 
     @Test
+    public void updateWindowManagerBrightnessOverride() {
+        var request = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+        request.brightness = 0.4f;
+        request.tag = "cts";
+        OverrideBrightnessStrategy overrideBrightnessStrategy = mock(
+                OverrideBrightnessStrategy.class);
+        when(mDisplayBrightnessStrategySelector.getOverrideBrightnessStrategy()).thenReturn(
+                overrideBrightnessStrategy);
+
+        when(overrideBrightnessStrategy.updateWindowManagerBrightnessOverride(any()))
+                .thenReturn(false);
+        assertFalse(mDisplayBrightnessController.updateWindowManagerBrightnessOverride(request));
+        verify(overrideBrightnessStrategy).updateWindowManagerBrightnessOverride(request);
+
+        when(overrideBrightnessStrategy.updateWindowManagerBrightnessOverride(any()))
+                .thenReturn(true);
+        assertTrue(mDisplayBrightnessController.updateWindowManagerBrightnessOverride(request));
+        verify(overrideBrightnessStrategy, times(2)).updateWindowManagerBrightnessOverride(request);
+    }
+
+    @Test
     public void setCurrentScreenBrightness() {
         // Current Screen brightness is set as expected when a different value than the current
         // is set
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index b99a18c..a647691 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -183,6 +183,8 @@
         when(mContext.getContentResolver()).thenReturn(contentResolver);
         when(mContext.getResources()).thenReturn(mResources);
         when(mInvalidBrightnessStrategy.getName()).thenReturn("InvalidBrightnessStrategy");
+        when(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+                .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
         mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
                 mInjector, DISPLAY_ID, mDisplayManagerFlags);
 
@@ -284,6 +286,20 @@
     }
 
     @Test
+    public void selectStrategySelectsOverrideStrategyWhenWindowManagerOverrideIsValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+        when(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride()).thenReturn(0.4f);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false, mDisplayOffloadSession,
+                                STYLUS_IS_NOT_BEING_USED, /* isBedtimeModeWearEnabled= */ false)),
+                mOverrideBrightnessStrategy);
+    }
+
+    @Test
     public void selectStrategySelectsTemporaryStrategyWhenValid() {
         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
                 DisplayManagerInternal.DisplayPowerRequest.class);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
index cc21af1..414f274a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
@@ -16,8 +16,9 @@
 
 package com.android.server.display.brightness.strategy;
 
+import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.hardware.display.DisplayManagerInternal;
 
@@ -34,7 +35,6 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-
 public class OverrideBrightnessStrategyTest {
     private OverrideBrightnessStrategy mOverrideBrightnessStrategy;
 
@@ -62,7 +62,56 @@
                         new StrategyExecutionRequest(displayPowerRequest, 0.2f,
                                 /* userSetBrightnessChanged= */ false,
                                 /* isStylusBeingUsed */ false));
-        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+        assertThat(updatedDisplayBrightnessState).isEqualTo(expectedDisplayBrightnessState);
     }
 
+    @Test
+    public void testUpdateBrightnessWhenWindowManagerOverrideIsRequested() {
+        var overrideRequest = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+        overrideRequest.brightness = 0.2f;
+        mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(overrideRequest);
+        DisplayManagerInternal.DisplayPowerRequest
+                displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+        displayPowerRequest.screenBrightnessOverride = BRIGHTNESS_INVALID_FLOAT;
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_OVERRIDE);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(overrideRequest.brightness)
+                        .setBrightnessReason(brightnessReason)
+                        .setDisplayBrightnessStrategyName(mOverrideBrightnessStrategy.getName())
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mOverrideBrightnessStrategy.updateBrightness(
+                        new StrategyExecutionRequest(displayPowerRequest, 0.2f,
+                                /* userSetBrightnessChanged= */ false,
+                                /* isStylusBeingUsed */ false));
+        assertThat(updatedDisplayBrightnessState).isEqualTo(expectedDisplayBrightnessState);
+    }
+
+    @Test
+    public void testUpdateWindowManagerBrightnessOverride() {
+        var request = new DisplayManagerInternal.DisplayBrightnessOverrideRequest();
+        assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+                .isFalse();
+        assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+                .isEqualTo(BRIGHTNESS_INVALID_FLOAT);
+
+        request.brightness = 0.2f;
+        assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+                .isTrue();
+        assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+                .isEqualTo(0.2f);
+
+        // Passing the same request doesn't result in an update.
+        assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(request))
+                .isFalse();
+        assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+                .isEqualTo(0.2f);
+
+        assertThat(mOverrideBrightnessStrategy.updateWindowManagerBrightnessOverride(null))
+                .isTrue();
+        assertThat(mOverrideBrightnessStrategy.getWindowManagerBrightnessOverride())
+                .isEqualTo(BRIGHTNESS_INVALID_FLOAT);
+    }
 }
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/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 1caa02a..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;
 
@@ -187,8 +188,8 @@
 
         doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
                 eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class));
-        doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), anyInt());
+        doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
+                eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class));
     }
 
     public void tearDown() throws Exception {
@@ -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/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 88caaa6..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(
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
                 eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+                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(
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
                 eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+                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(
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
                 eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+                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(
+        doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging(
                 eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE),
-                eq(getUidForPackage(PACKAGE_GREEN)));
+                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 a38ef78..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.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.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 f9f3790..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.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.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.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.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.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.LIMIT_PRIORITY_SCOPE), eq(getAppId(1)));
-        doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging(
-                eq(BroadcastRecord.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.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.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.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.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,7 +1000,7 @@
                         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)))));
     }
@@ -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/BackupAgentConnectionManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
new file mode 100644
index 0000000..19e43b6
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupAgentConnectionManagerTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ApplicationThreadConstants;
+import android.app.IActivityManager;
+import android.app.IBackupAgent;
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+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 androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.backup.internal.LifecycleOperationStorage;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import com.google.common.collect.ImmutableSet;
+
+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;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupAgentConnectionManagerTest {
+    private static final String TEST_PACKAGE = "com.test.package";
+
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Mock
+    IActivityManager mActivityManager;
+    @Mock
+    ActivityManagerInternal mActivityManagerInternal;
+    @Mock
+    LifecycleOperationStorage mOperationStorage;
+    @Mock
+    UserBackupManagerService mUserBackupManagerService;
+    @Mock
+    IBackupAgent.Stub mBackupAgentStub;
+    @Mock
+    PackageManager mPackageManager;
+
+    private BackupAgentConnectionManager mConnectionManager;
+    private MockitoSession mSession;
+    private ApplicationInfo mTestApplicationInfo;
+    private IBackupAgent mBackupAgentResult;
+    private Thread mTestThread;
+
+    @Before
+    public void setUp() throws Exception {
+        mSession = mockitoSession().initMocks(this).mockStatic(ActivityManager.class).mockStatic(
+                LocalServices.class).strictness(Strictness.LENIENT).startMocking();
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(mActivityManager).when(ActivityManager::getService);
+        doReturn(mActivityManagerInternal).when(
+                () -> LocalServices.getService(ActivityManagerInternal.class));
+        // Real package manager throws if a property is not defined.
+        when(mPackageManager.getPropertyAsUser(any(), any(), any(), anyInt())).thenThrow(
+                new PackageManager.NameNotFoundException());
+
+        mConnectionManager = spy(
+                new BackupAgentConnectionManager(mOperationStorage, mPackageManager,
+                        mUserBackupManagerService, UserHandle.USER_SYSTEM));
+
+        mTestApplicationInfo = new ApplicationInfo();
+        mTestApplicationInfo.packageName = TEST_PACKAGE;
+
+        mBackupAgentResult = null;
+        mTestThread = null;
+    }
+
+    @After
+    public void tearDown() {
+        if (mSession != null) {
+            mSession.finishMocking();
+        }
+    }
+
+    @Test
+    public void bindToAgentSynchronous_amReturnsFailure_returnsNullAndClearsPendingBackups()
+            throws Exception {
+        when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(false);
+
+        IBackupAgent result = mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        assertThat(result).isNull();
+        verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM);
+    }
+
+    @Test
+    public void bindToAgentSynchronous_agentDisconnectedCalled_returnsNullAndClearsPendingBackups()
+            throws Exception {
+        when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(true);
+        // This is so that IBackupAgent.Stub.asInterface() works.
+        when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub);
+        when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
+
+        // This is going to block until it receives the callback so we need to run it on a
+        // separate thread.
+        Thread testThread = new Thread(() -> setBackupAgentResult(
+                mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                        ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)),
+                "backup-agent-connection-manager-test");
+        testThread.start();
+        // Give the testThread a head start, otherwise agentConnected() might run before
+        // bindToAgentSynchronous() is called.
+        Thread.sleep(500);
+        mConnectionManager.agentDisconnected(TEST_PACKAGE);
+        testThread.join();
+
+        assertThat(mBackupAgentResult).isNull();
+        verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM);
+    }
+
+    @Test
+    public void bindToAgentSynchronous_agentConnectedCalled_returnsBackupAgent() throws Exception {
+        when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(true);
+        // This is so that IBackupAgent.Stub.asInterface() works.
+        when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub);
+        when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID);
+
+        // This is going to block until it receives the callback so we need to run it on a
+        // separate thread.
+        Thread testThread = new Thread(() -> setBackupAgentResult(
+                mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                        ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)),
+                "backup-agent-connection-manager-test");
+        testThread.start();
+        // Give the testThread a head start, otherwise agentConnected() might run before
+        // bindToAgentSynchronous() is called.
+        Thread.sleep(500);
+        mConnectionManager.agentConnected(TEST_PACKAGE, mBackupAgentStub);
+        testThread.join();
+
+        assertThat(mBackupAgentResult).isEqualTo(mBackupAgentStub);
+        verify(mActivityManagerInternal, never()).clearPendingBackup(anyInt());
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES)
+    public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode()
+            throws Exception {
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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 {
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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 {
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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 {
+        reset(mPackageManager);
+        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));
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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 {
+        reset(mPackageManager);
+        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));
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode() throws Exception {
+        reset(mPackageManager);
+        // 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());
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode()
+            throws Exception {
+        reset(mPackageManager);
+        // 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());
+        mConnectionManager.clearNoRestrictedModePackages();
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode()
+            throws Exception {
+        reset(mPackageManager);
+        // 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());
+        mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.RESTORE);
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                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({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE})
+    public void bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode()
+            throws Exception {
+        reset(mPackageManager);
+        // 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());
+        mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.BACKUP);
+
+        mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo,
+                ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD);
+
+        verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(),
+                /* useRestrictedMode= */ eq(false));
+    }
+
+    @Test
+    public void agentDisconnected_cancelsCurrentOperations() throws Exception {
+        when(mOperationStorage.operationTokensForPackage(eq(TEST_PACKAGE))).thenReturn(
+                ImmutableSet.of(123, 456, 789));
+        when(mConnectionManager.getThreadForCancellation(any())).thenAnswer(invocation -> {
+            Thread testThread = new Thread((Runnable) invocation.getArgument(0),
+                    "agent-disconnected-test");
+            setTestThread(testThread);
+            return testThread;
+        });
+
+        mConnectionManager.agentDisconnected(TEST_PACKAGE);
+
+        mTestThread.join();
+        verify(mUserBackupManagerService).handleCancel(eq(123), eq(true));
+        verify(mUserBackupManagerService).handleCancel(eq(456), eq(true));
+        verify(mUserBackupManagerService).handleCancel(eq(789), eq(true));
+    }
+
+    @Test
+    public void unbindAgent_callsAmUnbindBackupAgent() throws Exception {
+        mConnectionManager.unbindAgent(mTestApplicationInfo);
+
+        verify(mActivityManager).unbindBackupAgent(eq(mTestApplicationInfo));
+    }
+
+    // Needed because variables can't be assigned directly inside lambdas in Java.
+    private void setBackupAgentResult(IBackupAgent result) {
+        mBackupAgentResult = result;
+    }
+
+    // Needed because variables can't be assigned directly inside lambdas in Java.
+    private void setTestThread(Thread thread) {
+        mTestThread = thread;
+    }
+}
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..7a9e96f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -21,38 +21,38 @@
 
 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;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.when;
 
 import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+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.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.testing.TestableContext;
 import android.util.FeatureFlagUtils;
 import android.util.KeyValueListParser;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.internal.BackupHandler;
@@ -64,11 +64,11 @@
 import com.android.server.backup.utils.BackupEligibilityRules;
 import com.android.server.backup.utils.BackupManagerMonitorEventSender;
 
-import com.google.common.collect.ImmutableSet;
-
 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,7 +77,6 @@
 
 import java.util.Arrays;
 import java.util.List;
-import java.util.function.IntConsumer;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -85,9 +84,13 @@
     private static final String TEST_PACKAGE = "package1";
     private static final String[] TEST_PACKAGES = new String[] { TEST_PACKAGE };
     private static final String TEST_TRANSPORT = "transport";
-    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 +102,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 +127,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() {
@@ -256,33 +265,6 @@
     }
 
     @Test
-    @FlakyTest
-    public void testAgentDisconnected_cancelsCurrentOperations() throws Exception {
-        when(mOperationStorage.operationTokensForPackage(eq("com.android.foo"))).thenReturn(
-                ImmutableSet.of(123, 456, 789)
-        );
-
-        mService.agentDisconnected("com.android.foo");
-
-        mService.waitForAsyncOperation();
-        verify(mOperationStorage).cancelOperation(eq(123), eq(true), any(IntConsumer.class));
-        verify(mOperationStorage).cancelOperation(eq(456), eq(true), any());
-        verify(mOperationStorage).cancelOperation(eq(789), eq(true), any());
-    }
-
-    @Test
-    public void testAgentDisconnected_unknownPackageName_cancelsNothing() throws Exception {
-        when(mOperationStorage.operationTokensForPackage(eq("com.android.foo"))).thenReturn(
-                ImmutableSet.of()
-        );
-
-        mService.agentDisconnected("com.android.foo");
-
-        verify(mOperationStorage, never())
-                .cancelOperation(anyInt(), anyBoolean(), any(IntConsumer.class));
-    }
-
-    @Test
     public void testReportDelayedRestoreResult_sendsLogsToMonitor() throws Exception {
         PackageInfo packageInfo = getPackageInfo(TEST_PACKAGE);
         when(mPackageManager.getPackageInfoAsUser(anyString(),
@@ -298,9 +280,8 @@
                 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));
     }
 
     private static PackageInfo getPackageInfo(String packageName) {
@@ -314,13 +295,9 @@
         boolean isEnabledStatePersisted = false;
         boolean shouldUseNewBackupEligibilityRules = false;
 
-        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) {
@@ -352,26 +329,8 @@
         }
 
         @Override
-        Thread getThreadForAsyncOperation(String operationName, Runnable operation) {
-            mWorkerThread = super.getThreadForAsyncOperation(operationName, operation);
-            return mWorkerThread;
-        }
-
-        @Override
         BackupManagerMonitorEventSender getBMMEventSender(IBackupManagerMonitor monitor) {
             return mBackupManagerMonitorEventSender;
         }
-
-        private void waitForAsyncOperation() {
-            if (mWorkerThread == null) {
-                return;
-            }
-
-            try {
-                mWorkerThread.join(/* millis */ WORKER_THREAD_TIMEOUT_MILLISECONDS);
-            } catch (InterruptedException e) {
-                fail("Failed waiting for worker thread to complete: " + e.getMessage());
-            }
-        }
     }
 }
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..e618433 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,100 @@
 
 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.BackupAgentConnectionManager;
+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
+    BackupAgentConnectionManager mBackupAgentConnectionManager;
+    @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.getBackupAgentConnectionManager()).thenReturn(
+                mBackupAgentConnectionManager);
         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 +136,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(mBackupAgentConnectionManager);
+        inOrder.verify(mBackupAgentConnectionManager).setNoRestrictedModePackages(
+                eq(Set.of("package1")),
+                eq(BackupAnnotations.OperationType.BACKUP));
+        inOrder.verify(mBackupAgentConnectionManager).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..351aac3 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;
@@ -42,6 +44,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.modules.utils.testing.TestableDeviceConfig;
+import com.android.server.backup.BackupAgentConnectionManager;
 import com.android.server.backup.Flags;
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.internal.BackupHandler;
@@ -91,6 +94,10 @@
     private UserBackupManagerService mBackupManagerService;
     @Mock
     private TransportConnection mTransportConnection;
+    @Mock
+    private BackupTransportClient mBackupTransportClient;
+    @Mock
+    private BackupAgentConnectionManager mBackupAgentConnectionManager;
 
     private Set<String> mExcludedkeys = new HashSet<>();
     private Map<String, String> mBackupData = new HashMap<>();
@@ -118,6 +125,9 @@
 
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
 
+        when(mBackupManagerService.getBackupAgentConnectionManager()).thenReturn(
+                mBackupAgentConnectionManager);
+
         mBackupDataSource = new ArrayDeque<>(mBackupData.keySet());
         when(mBackupDataInput.readNextHeader())
                 .then((Answer<Boolean>) invocation -> !mBackupDataSource.isEmpty());
@@ -151,6 +161,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(mBackupAgentConnectionManager).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/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index d66bb00..c6870ad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -65,6 +65,7 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -103,10 +104,13 @@
 import com.android.server.job.controllers.QuotaController.TimingSession;
 import com.android.server.usage.AppStandbyInternal;
 
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
 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.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
@@ -135,6 +139,9 @@
     private static final int SOURCE_USER_ID = 0;
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
     private QuotaController mQuotaController;
     private QuotaController.QcConstants mQcConstants;
     private JobSchedulerService.Constants mConstants = new JobSchedulerService.Constants();
@@ -303,7 +310,7 @@
 
     private int getProcessStateQuotaFreeThreshold() {
         synchronized (mQuotaController.mLock) {
-            return mQuotaController.getProcessStateQuotaFreeThreshold();
+            return mQuotaController.getProcessStateQuotaFreeThreshold(mSourceUid);
         }
     }
 
@@ -5197,6 +5204,101 @@
         assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
     }
 
+    @Test
+    @EnableCompatChanges({QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_TOP_STARTED_JOBS,
+            QuotaController.OVERRIDE_QUOTA_ENFORCEMENT_TO_FGS_JOBS})
+    @RequiresFlagsEnabled({Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_TOP_STARTED_JOBS,
+            Flags.FLAG_ENFORCE_QUOTA_POLICY_TO_FGS_JOBS})
+    public void testTracking_OutOfQuota_ForegroundAndBackground_CompactChangeOverrides() {
+        setDischarging();
+
+        JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
+        JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
+        trackJobs(jobBg, jobTop);
+        setStandbyBucket(WORKING_INDEX, jobTop, jobBg); // 2 hour window
+        // Now the package only has 20 seconds to run.
+        final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1), false);
+
+        InOrder inOrder = inOrder(mJobSchedulerService);
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        // Start the job.
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg);
+        }
+        advanceElapsedClock(remainingTimeMs / 2);
+        // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+        // should continue to have remainingTimeMs / 2 time remaining.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop);
+        }
+        advanceElapsedClock(remainingTimeMs);
+
+        // Wait for some extra time to allow for job processing.
+        inOrder.verify(mJobSchedulerService,
+                        timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+                .onControllerStateChanged(argThat(jobs -> jobs.size() > 0));
+        synchronized (mQuotaController.mLock) {
+            assertEquals(remainingTimeMs / 2,
+                    mQuotaController.getRemainingExecutionTimeLocked(jobBg));
+            assertEquals(remainingTimeMs / 2,
+                    mQuotaController.getRemainingExecutionTimeLocked(jobTop));
+        }
+        // Go to a background state.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        advanceElapsedClock(remainingTimeMs / 2 + 1);
+        // Only Bg job will be changed from in-quota to out-of-quota.
+        inOrder.verify(mJobSchedulerService,
+                        timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged(argThat(jobs -> jobs.size() == 1));
+        // Top job should still be allowed to run.
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // New jobs to run.
+        JobStatus jobBg2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 3);
+        JobStatus jobTop2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 4);
+        JobStatus jobFg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 5);
+        setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged(argThat(jobs -> jobs.size() == 1));
+        trackJobs(jobFg, jobTop);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop);
+        }
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // App still in foreground so everything should be in quota.
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged(argThat(jobs -> jobs.size() == 2));
+        // App is now in background and out of quota. Fg should now change to out of quota since it
+        // wasn't started. Top should remain in quota since it started when the app was in TOP.
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        trackJobs(jobBg2);
+        assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+    }
+
     /**
      * Tests that TOP jobs are stopped when an app runs out of quota.
      */
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/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/src/com/android/server/accessibility/FlashNotificationsControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
index 0988eea..a55346c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java
@@ -430,7 +430,7 @@
         AudioPlaybackConfiguration config = new AudioPlaybackConfiguration(
                 mock(PlayerBase.PlayerIdCard.class), 0, 0, 0);
         config.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_STARTED,
-                AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+                AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID);
 
         AudioAttributes.Builder builder = new AudioAttributes.Builder();
         builder.setUsage(AudioAttributes.USAGE_ALARM);
diff --git a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
index 84c0ab3..0d44021 100644
--- a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java
@@ -314,12 +314,13 @@
         AudioDeviceInfo[] devicesStatic = AudioManager.getDevicesStatic(GET_DEVICES_OUTPUTS);
         assumeTrue(devIdx < devicesStatic.length);
         Log.d(TAG, "Out devices number " + devicesStatic.length + ". Picking index " + devIdx);
-        int deviceId = devicesStatic[devIdx].getId();
+        int[] deviceIds = new int[1];
+        deviceIds[0] = devicesStatic[devIdx].getId();
 
         PlayerBase.PlayerIdCard idCard = Mockito.mock(PlayerBase.PlayerIdCard.class);
         AudioPlaybackConfiguration apc =
                 new AudioPlaybackConfiguration(idCard, piid, /*uid=*/1, /*pid=*/myPid());
-        apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceId);
+        apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceIds);
         apc.handleSessionIdEvent(sessionId);
         apc.handleAudioAttributesEvent(new AudioAttributes.Builder()
                 .setUsage(AudioAttributes.USAGE_MEDIA)
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/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 51c2ad1..687a1ab 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -200,7 +200,9 @@
             AudioPlaybackConfiguration audioPlaybackConfiguration =
                     new AudioPlaybackConfiguration(
                             playerIdCard, /* piid= */ 1000, appUid, /* pid= */ 1000);
-            audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, /* deviceId= */1);
+            int[] deviceIds = new int[1];
+            deviceIds[0] = 1;
+            audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, deviceIds);
             configs.add(audioPlaybackConfiguration);
         }
         return configs;
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 9524fb2..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;
@@ -4903,6 +4912,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_profileOwner() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4931,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;
 
@@ -4949,6 +4960,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_nonOwner() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4965,6 +4977,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED)
     public void testSecondaryLockscreen_nonSupervisionApp() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
@@ -4997,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..b2a7d20 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 =
@@ -706,7 +664,7 @@
                 mClockInjector);
         MediaProjectionManagerService.MediaProjection projection = createProjectionPreconditions(
                 service);
-        mClock.fastForward(projection.mDefaultTimeoutMs + 10);
+        mClock.fastForward(projection.mDefaultTimeoutMillis + 10);
 
         // Immediate timeout - so no longer valid.
         assertThat(projection.isValid()).isFalse();
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 89%
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..ee8eb9b 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,17 +14,19 @@
  * 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 android.security.authenticationpolicy.AuthenticationPolicyManager.ERROR_UNSUPPORTED;
 
 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;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -66,12 +68,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 +83,7 @@
     private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason
 
     private Context mContext;
-    private AdaptiveAuthenticationService mAdaptiveAuthenticationService;
+    private AuthenticationPolicyService mAuthenticationPolicyService;
 
     @Mock
     LockPatternUtils mLockPatternUtils;
@@ -95,6 +97,8 @@
     private WindowManagerInternal mWindowManager;
     @Mock
     private UserManagerInternal mUserManager;
+    @Mock
+    private SecureLockDeviceServiceInternal mSecureLockDeviceService;
 
     @Captor
     ArgumentCaptor<LockSettingsStateListener> mLockSettingsStateListenerCaptor;
@@ -123,10 +127,15 @@
         LocalServices.addService(WindowManagerInternal.class, mWindowManager);
         LocalServices.removeServiceForTest(UserManagerInternal.class);
         LocalServices.addService(UserManagerInternal.class, mUserManager);
+        if (android.security.Flags.secureLockdown()) {
+            LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class);
+            LocalServices.addService(SecureLockDeviceServiceInternal.class,
+                    mSecureLockDeviceService);
+        }
 
-        mAdaptiveAuthenticationService = new AdaptiveAuthenticationService(
+        mAuthenticationPolicyService = new AuthenticationPolicyService(
                 mContext, mLockPatternUtils);
-        mAdaptiveAuthenticationService.init();
+        mAuthenticationPolicyService.init();
 
         verify(mLockSettings).registerLockSettingsStateListener(
                 mLockSettingsStateListenerCaptor.capture());
@@ -136,6 +145,12 @@
         // Set PRIMARY_USER_ID as the parent of MANAGED_PROFILE_USER_ID
         when(mUserManager.getProfileParentId(eq(MANAGED_PROFILE_USER_ID)))
                 .thenReturn(PRIMARY_USER_ID);
+        if (android.security.Flags.secureLockdown()) {
+            when(mSecureLockDeviceService.enableSecureLockDevice(any()))
+                    .thenReturn(ERROR_UNSUPPORTED);
+            when(mSecureLockDeviceService.disableSecureLockDevice(any()))
+                    .thenReturn(ERROR_UNSUPPORTED);
+        }
     }
 
     @After
@@ -143,6 +158,9 @@
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.removeServiceForTest(UserManagerInternal.class);
+        if (android.security.Flags.secureLockdown()) {
+            LocalServices.removeServiceForTest(SecureLockDeviceServiceInternal.class);
+        }
     }
 
     @Test
@@ -318,13 +336,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/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 020670d..bf61d06 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -72,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;
@@ -201,9 +202,6 @@
 import org.mockito.MockitoAnnotations;
 import org.xmlpull.v1.XmlPullParserException;
 
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -223,6 +221,9 @@
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 @SmallTest
 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
 @RunWith(ParameterizedAndroidJunit4.class)
@@ -7067,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/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 3c2f961..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,6 +747,23 @@
     }
 
     @Test
+    @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
+    public void vibrate_singleVibratorComposedAndNoCapability_triggersHalAndReturnsUnsupported() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+                .compose();
+        HalVibration vibration = startThreadAndDispatcher(effect);
+        waitForCompletion();
+
+        verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
+        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
+    @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY)
     public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() {
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
@@ -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();
 
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 5f76d68..ec83e99 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -2865,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)
@@ -2889,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);
@@ -3139,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);
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 6e6b70d..5f2f3ed 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -17,10 +17,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.frameworks.wmtests">
 
-    <!-- Uses API introduced in P (28) -->
+    <!-- Uses API introduced in S (31). Using SDK 31+ avoids Google Play Protect popups. -->
     <uses-sdk
         android:minSdkVersion="1"
-        android:targetSdkVersion="28" />
+        android:targetSdkVersion="31" />
 
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
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/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
index b91a5b7..d5ed048 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -17,8 +17,8 @@
 package com.android.server.wm;
 
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
 import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -228,9 +228,8 @@
     }
 
     @Test
-    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+    public void testShouldApplyCameraCompatFreeformTreatment_notEnabledByOverride_returnsFalse() {
         runTestScenario((robot) -> {
             robot.activity().createActivityWithComponentInNewTask();
 
@@ -239,19 +238,9 @@
     }
 
     @Test
-    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse() {
-        runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponentInNewTask();
-
-            robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
-        });
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
+    public void testShouldApplyCameraCompatFreeformTreatment_overrideAndFlagEnabled_returnsTrue() {
         runTestScenario((robot) -> {
             robot.activity().createActivityWithComponentInNewTask();
 
@@ -261,8 +250,9 @@
 
     @Test
     @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA,
-            OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
-    public void testShouldRecomputeConfigurationForCameraCompat() {
+            OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA,
+            OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+    public void testShouldRecomputeConfigurationForFreeformTreatment() {
         runTestScenario((robot) -> {
             robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
             robot.applyOnActivity((a) -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index e447565..c427583 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -25,7 +25,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -96,61 +96,55 @@
     private static final String TEST_PACKAGE_1 = "com.android.frameworks.wmtests";
     private static final String TEST_PACKAGE_2 = "com.test.package.two";
     private static final String CAMERA_ID_1 = "camera-1";
-    private static final String CAMERA_ID_2 = "camera-2";
-    private CameraManager mMockCameraManager;
-    private Handler mMockHandler;
     private AppCompatConfiguration mAppCompatConfiguration;
 
     private CameraManager.AvailabilityCallback mCameraAvailabilityCallback;
     private CameraCompatFreeformPolicy mCameraCompatFreeformPolicy;
     private ActivityRecord mActivity;
-    private Task mTask;
     private ActivityRefresher mActivityRefresher;
 
     @Before
     public void setUp() throws Exception {
         mAppCompatConfiguration = mDisplayContent.mWmService.mAppCompatConfiguration;
         spyOn(mAppCompatConfiguration);
-        when(mAppCompatConfiguration.isCameraCompatTreatmentEnabled())
-                .thenReturn(true);
-        when(mAppCompatConfiguration.isCameraCompatRefreshEnabled())
-                .thenReturn(true);
+        when(mAppCompatConfiguration.isCameraCompatTreatmentEnabled()).thenReturn(true);
+        when(mAppCompatConfiguration.isCameraCompatRefreshEnabled()).thenReturn(true);
         when(mAppCompatConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
                 .thenReturn(true);
 
-        mMockCameraManager = mock(CameraManager.class);
+        final CameraManager mockCameraManager = mock(CameraManager.class);
         doAnswer(invocation -> {
             mCameraAvailabilityCallback = invocation.getArgument(1);
             return null;
-        }).when(mMockCameraManager).registerAvailabilityCallback(
+        }).when(mockCameraManager).registerAvailabilityCallback(
                 any(Executor.class), any(CameraManager.AvailabilityCallback.class));
 
-        when(mContext.getSystemService(CameraManager.class)).thenReturn(mMockCameraManager);
+        when(mContext.getSystemService(CameraManager.class)).thenReturn(mockCameraManager);
 
         mDisplayContent.setIgnoreOrientationRequest(true);
 
-        mMockHandler = mock(Handler.class);
+        final Handler mockHandler = mock(Handler.class);
 
-        when(mMockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
+        when(mockHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
                 invocation -> {
                     ((Runnable) invocation.getArgument(0)).run();
                     return null;
                 });
 
-        mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mMockHandler);
-        CameraStateMonitor cameraStateMonitor =
-                new CameraStateMonitor(mDisplayContent, mMockHandler);
-        mCameraCompatFreeformPolicy =
-                new CameraCompatFreeformPolicy(mDisplayContent, cameraStateMonitor,
-                        mActivityRefresher);
+        mActivityRefresher = new ActivityRefresher(mDisplayContent.mWmService, mockHandler);
+        final CameraStateMonitor cameraStateMonitor = new CameraStateMonitor(mDisplayContent,
+                mockHandler);
+        mCameraCompatFreeformPolicy = new CameraCompatFreeformPolicy(mDisplayContent,
+                cameraStateMonitor, mActivityRefresher);
 
         setDisplayRotation(Surface.ROTATION_90);
         mCameraCompatFreeformPolicy.start();
         cameraStateMonitor.startListeningToCameraState();
     }
 
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testFullscreen_doesNotActivateCameraCompatMode() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT, WINDOWING_MODE_FULLSCREEN);
         doReturn(false).when(mActivity).inFreeformWindowingMode();
@@ -160,23 +154,26 @@
         assertNotInCameraCompatMode();
     }
 
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testOrientationUnspecified_doesNotActivateCameraCompatMode() {
         configureActivity(SCREEN_ORIENTATION_UNSPECIFIED);
 
         assertNotInCameraCompatMode();
     }
 
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testNoCameraConnection_doesNotActivateCameraCompatMode() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         assertNotInCameraCompatMode();
     }
 
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraConnected_deviceInPortrait_portraitCameraCompatMode() throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         setDisplayRotation(Surface.ROTATION_0);
@@ -187,6 +184,8 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraConnected_deviceInLandscape_portraitCameraCompatMode() throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         setDisplayRotation(Surface.ROTATION_270);
@@ -197,6 +196,8 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraConnected_deviceInPortrait_landscapeCameraCompatMode() throws Exception {
         configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
         setDisplayRotation(Surface.ROTATION_0);
@@ -207,6 +208,8 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraConnected_deviceInLandscape_landscapeCameraCompatMode() throws Exception {
         configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
         setDisplayRotation(Surface.ROTATION_270);
@@ -216,8 +219,9 @@
         assertActivityRefreshRequested(/* refreshRequested */ false);
     }
 
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraReconnected_cameraCompatModeAndRefresh() throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         setDisplayRotation(Surface.ROTATION_270);
@@ -236,6 +240,8 @@
     }
 
     @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testCameraOpenedForDifferentPackage_notInCameraCompatMode() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
 
@@ -246,27 +252,32 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
-    public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+    public void testShouldApplyCameraCompatFreeformTreatment_overrideNotEnabled_returnsFalse() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
 
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertFalse(mCameraCompatFreeformPolicy.isTreatmentEnabledForActivity(mActivity,
+                /* checkOrientation */ true));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges(OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT)
+    public void testShouldApplyCameraCompatFreeformTreatment_enabledByOverride_returnsTrue() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
         assertTrue(mActivity.info
-                .isChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT));
-        assertFalse(mCameraCompatFreeformPolicy.isCameraCompatForFreeformEnabledForActivity(
-                mActivity));
+                .isChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT));
+        assertTrue(mCameraCompatFreeformPolicy.isTreatmentEnabledForActivity(mActivity,
+                /* checkOrientation */ true));
     }
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
-    public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
-        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
-
-        assertTrue(mCameraCompatFreeformPolicy.isCameraCompatForFreeformEnabledForActivity(
-                mActivity));
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testShouldRefreshActivity_appBoundsChanged_returnsTrue() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         Configuration oldConfiguration = createConfiguration(/* letterbox= */ false);
@@ -279,6 +290,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testShouldRefreshActivity_displayRotationChanged_returnsTrue() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
@@ -294,6 +306,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testShouldRefreshActivity_appBoundsNorDisplayChanged_returnsFalse() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         Configuration oldConfiguration = createConfiguration(/* letterbox= */ true);
@@ -309,6 +322,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testOnActivityConfigurationChanging_refreshDisabledViaFlag_noRefresh()
             throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -324,6 +338,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testOnActivityConfigurationChanging_cycleThroughStopDisabled() throws Exception {
         when(mAppCompatConfiguration.isCameraCompatRefreshCycleThroughStopEnabled())
                 .thenReturn(false);
@@ -338,6 +353,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
             throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
@@ -352,6 +368,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testGetCameraCompatAspectRatio_activityNotInCameraCompat_returnsDefaultAspRatio() {
         configureActivity(SCREEN_ORIENTATION_FULL_USER);
 
@@ -365,6 +382,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testGetCameraCompatAspectRatio_activityInCameraCompat_returnsConfigAspectRatio() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         final float configAspectRatio = 1.5f;
@@ -380,6 +398,7 @@
 
     @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testGetCameraCompatAspectRatio_inCameraCompatPerAppOverride_returnDefAspectRatio() {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
         final float configAspectRatio = 1.5f;
@@ -406,7 +425,7 @@
 
     private void configureActivityAndDisplay(@ScreenOrientation int activityOrientation,
             @Orientation int naturalOrientation, @WindowingMode int windowingMode) {
-        mTask = new TaskBuilder(mSupervisor)
+        final Task task = new TaskBuilder(mSupervisor)
                 .setDisplay(mDisplayContent)
                 .setWindowingMode(windowingMode)
                 .build();
@@ -416,7 +435,7 @@
                 .setComponent(ComponentName.createRelative(mContext,
                         com.android.server.wm.CameraCompatFreeformPolicyTests.class.getName()))
                 .setScreenOrientation(activityOrientation)
-                .setTask(mTask)
+                .setTask(task)
                 .build();
 
         spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
@@ -429,13 +448,11 @@
     }
 
     private void assertInCameraCompatMode(@CameraCompatTaskInfo.FreeformCameraCompatMode int mode) {
-        assertEquals(mode, mActivity.mAppCompatController.getAppCompatCameraOverrides()
-                        .getFreeformCameraCompatMode());
+        assertEquals(mode, mCameraCompatFreeformPolicy.getCameraCompatMode(mActivity));
     }
 
     private void assertNotInCameraCompatMode() {
-        assertEquals(CAMERA_COMPAT_FREEFORM_NONE, mActivity.mAppCompatController
-                .getAppCompatCameraOverrides().getFreeformCameraCompatMode());
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_NONE);
     }
 
     private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -471,7 +488,8 @@
 
     private Configuration createConfiguration(boolean letterbox) {
         final Configuration configuration = new Configuration();
-        Rect bounds = letterbox ? new Rect(300, 0, 700, 600) : new Rect(0, 0, 1000, 600);
+        Rect bounds = letterbox ? new Rect(/*left*/ 300, /*top*/ 0, /*right*/ 700, /*bottom*/ 600)
+                : new Rect(/*left*/ 0, /*top*/ 0, /*right*/ 1000, /*bottom*/ 600);
         configuration.windowConfiguration.setAppBounds(bounds);
         return configuration;
     }
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 b737d35..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;
@@ -1557,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/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl
new file mode 100644
index 0000000..1e41d6e
--- /dev/null
+++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony;
+
+parcelable CellularIdentifierDisclosure;
diff --git a/telephony/java/android/telephony/CellularIdentifierDisclosure.java b/telephony/java/android/telephony/CellularIdentifierDisclosure.java
index 7b2db6d..0b6a70f 100644
--- a/telephony/java/android/telephony/CellularIdentifierDisclosure.java
+++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.java
@@ -16,11 +16,16 @@
 
 package android.telephony;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -31,16 +36,88 @@
  *
  * @hide
  */
+@SystemApi
+@FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS)
 public final class CellularIdentifierDisclosure implements Parcelable {
     private static final String TAG = "CellularIdentifierDisclosure";
 
+    /* Non-access stratum protocol messages */
+    /** Unknown */
+    public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0;
+    /** ATTACH REQUESTS. Sample reference: TS 24.301 8.2.4 Applies to 2g, 3g, and 4g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1;
+    /** IDENTITY RESPONSE. Sample Reference: TS 24.301 8.2.19.
+     * Applies to 2g, 3g, 4g, and 5g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2;
+    /** DETACH_REQUEST. Sample Reference: TS 24.301 8.2.11. Applies to 2g, 3g, and 4g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3;
+    /** TRACKING AREA UPDATE (TAU) REQUEST. Sample Reference: 3GPP TS 24.301 8.2.29.
+     * Note: that per the spec, only temporary IDs should be sent in the TAU Request, but since the
+     * EPS Mobile Identity field supports IMSIs, this is included as an extra safety measure to
+     * combat implementation bugs. Applies to 4g and 5g networks. */
+    public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4;
+    /** LOCATION UPDATE REQUEST. Sample Reference: TS 24.008 4.4.3. Applies to 2g and 3g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5;
+    /** AUTHENTICATION AND CIPHERING RESPONSE. Reference: 3GPP TS 24.008 4.7.7.1.
+     * Applies to 2g and 3g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6;
+    /** REGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.6. Applies to 5g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7;
+    /** DEREGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.12. Applies to 5g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8;
+    /** CONNECTION MANAGEMENT REESTABLISHMENT REQUEST. Reference: 3GPP TS 24.008 9.2.4.
+     * Applies to 2g and 3g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9;
+    /** CONNECTION MANAGEMENT SERVICE REQUEST. Reference: 3GPP TS 24.008 9.2.9.
+     * Applies to 2g and 3g networks */
+    public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10;
+    /** IMEI DETATCH INDICATION. Reference: 3GPP TS 24.008 9.2.14.
+     * Applies to 2g and 3g networks. Used for circuit-switched detach. */
+    public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN,
+            NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE,
+            NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST,
+            NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST,
+            NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE,
+            NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST,
+            NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST,
+            NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION})
+    public @interface NasProtocolMessage {
+    }
+
+    /* Cellular identifiers */
+    /** Unknown */
+    public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0;
+    /** IMSI (International Mobile Subscriber Identity) */
+    public static final int CELLULAR_IDENTIFIER_IMSI = 1;
+    /** IMEI (International Mobile Equipment Identity) */
+    public static final int CELLULAR_IDENTIFIER_IMEI = 2;
+    /** 5G-specific SUCI (Subscription Concealed Identifier) */
+    public static final int CELLULAR_IDENTIFIER_SUCI = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN,
+            CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI})
+    public @interface CellularIdentifier {
+    }
+
     private @NasProtocolMessage int mNasProtocolMessage;
     private @CellularIdentifier int mCellularIdentifier;
     private String mPlmn;
     private boolean mIsEmergency;
 
+    /**
+     * Constructor for new CellularIdentifierDisclosure instances.
+     *
+     * @hide
+     */
+    @TestApi
     public CellularIdentifierDisclosure(@NasProtocolMessage int nasProtocolMessage,
-            @CellularIdentifier int cellularIdentifier, String plmn, boolean isEmergency) {
+            @CellularIdentifier int cellularIdentifier, @NonNull String plmn, boolean isEmergency) {
         mNasProtocolMessage = nasProtocolMessage;
         mCellularIdentifier = cellularIdentifier;
         mPlmn = plmn;
@@ -51,18 +128,30 @@
         readFromParcel(in);
     }
 
+    /**
+     * @return the NAS protocol message associated with the disclosed identifier.
+     */
     public @NasProtocolMessage int getNasProtocolMessage() {
         return mNasProtocolMessage;
     }
 
+    /**
+     * @return the identifier disclosed.
+     */
     public @CellularIdentifier int getCellularIdentifier() {
         return mCellularIdentifier;
     }
 
-    public String getPlmn() {
+    /**
+     * @return the PLMN associated with the disclosure.
+     */
+    @NonNull public String getPlmn() {
         return mPlmn;
     }
 
+    /**
+     * @return if the disclosure is associated with an emergency call.
+     */
     public boolean isEmergency() {
         return mIsEmergency;
     }
@@ -73,14 +162,14 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(mNasProtocolMessage);
         out.writeInt(mCellularIdentifier);
         out.writeBoolean(mIsEmergency);
         out.writeString8(mPlmn);
     }
 
-    public static final Parcelable.Creator<CellularIdentifierDisclosure> CREATOR =
+    public static final @NonNull Parcelable.Creator<CellularIdentifierDisclosure> CREATOR =
             new Parcelable.Creator<CellularIdentifierDisclosure>() {
                 public CellularIdentifierDisclosure createFromParcel(Parcel in) {
                     return new CellularIdentifierDisclosure(in);
@@ -120,42 +209,4 @@
         mIsEmergency = in.readBoolean();
         mPlmn = in.readString8();
     }
-
-    public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0;
-    public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1;
-    public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2;
-    public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3;
-    public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4;
-    public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5;
-    public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6;
-    public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7;
-    public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8;
-    public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9;
-    public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10;
-    public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN,
-            NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE,
-            NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST,
-            NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST,
-            NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE,
-            NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST,
-            NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST,
-            NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION})
-    public @interface NasProtocolMessage {
-    }
-
-    public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0;
-    public static final int CELLULAR_IDENTIFIER_IMSI = 1;
-    public static final int CELLULAR_IDENTIFIER_IMEI = 2;
-    public static final int CELLULAR_IDENTIFIER_SUCI = 3;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN,
-            CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI})
-    public @interface CellularIdentifier {
-    }
 }
diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl
new file mode 100644
index 0000000..bee30bd
--- /dev/null
+++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony;
+
+parcelable SecurityAlgorithmUpdate;
diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
index 57209eb..d635b55 100644
--- a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
+++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java
@@ -16,11 +16,16 @@
 
 package android.telephony;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -31,14 +36,189 @@
  *
  * @hide
  */
+@SystemApi
+@FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS)
 public final class SecurityAlgorithmUpdate implements Parcelable {
     private static final String TAG = "SecurityAlgorithmUpdate";
 
+    /** 2G GSM circuit switched */
+    public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0;
+    /** 2G GPRS packet services */
+    public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1;
+    /** 3G circuit switched*/
+    public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2;
+    /** 3G packet switched*/
+    public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3;
+    /** 4G Non-access stratum */
+    public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4;
+    /** 4G Access-stratum */
+    public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5;
+    /** VOLTE SIP */
+    public static final int CONNECTION_EVENT_VOLTE_SIP = 6;
+    /** VOLTE SIP SOS (emergency) */
+    public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7;
+    /** VOLTE RTP */
+    public static final int CONNECTION_EVENT_VOLTE_RTP = 8;
+    /** VOLTE RTP SOS (emergency) */
+    public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9;
+    /** 5G Non-access stratum */
+    public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10;
+    /** 5G Access stratum */
+    public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11;
+    /** VoNR SIP */
+    public static final int CONNECTION_EVENT_VONR_SIP = 12;
+    /** VoNR SIP SOS (emergency) */
+    public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13;
+    /** VoNR RTP */
+    public static final int CONNECTION_EVENT_VONR_RTP = 14;
+    /** VoNR RTP SOS (emergency) */
+    public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {CONNECTION_EVENT_CS_SIGNALLING_GSM,
+            CONNECTION_EVENT_PS_SIGNALLING_GPRS, CONNECTION_EVENT_CS_SIGNALLING_3G,
+            CONNECTION_EVENT_PS_SIGNALLING_3G, CONNECTION_EVENT_NAS_SIGNALLING_LTE,
+            CONNECTION_EVENT_AS_SIGNALLING_LTE, CONNECTION_EVENT_VOLTE_SIP,
+            CONNECTION_EVENT_VOLTE_SIP_SOS, CONNECTION_EVENT_VOLTE_RTP,
+            CONNECTION_EVENT_VOLTE_RTP_SOS, CONNECTION_EVENT_NAS_SIGNALLING_5G,
+            CONNECTION_EVENT_AS_SIGNALLING_5G, CONNECTION_EVENT_VONR_SIP,
+            CONNECTION_EVENT_VONR_SIP_SOS, CONNECTION_EVENT_VONR_RTP,
+            CONNECTION_EVENT_VONR_RTP_SOS})
+    public @interface ConnectionEvent {
+    }
+
+    /* GSM CS services, see 3GPP TS 43.020 for details */
+    /** A5/0 - the null cipher */
+    public static final int SECURITY_ALGORITHM_A50 = 0;
+    /** A5/1 cipher */
+    public static final int SECURITY_ALGORITHM_A51 = 1;
+    /** A5/2 cipher */
+    public static final int SECURITY_ALGORITHM_A52 = 2;
+    /** A5/3 cipher */
+    public static final int SECURITY_ALGORITHM_A53 = 3;
+    /** A5/4 cipher */
+    public static final int SECURITY_ALGORITHM_A54 = 4;
+    /* GPRS PS services (3GPP TS 43.020) */
+    /** GEA0 - null cipher */
+    public static final int SECURITY_ALGORITHM_GEA0 = 14;
+    /** GEA1 cipher */
+    public static final int SECURITY_ALGORITHM_GEA1 = 15;
+    /** GEA2 cipher */
+    public static final int SECURITY_ALGORITHM_GEA2 = 16;
+    /** GEA3 cipher */
+    public static final int SECURITY_ALGORITHM_GEA3 = 17;
+    /** GEA4 cipher */
+    public static final int SECURITY_ALGORITHM_GEA4 = 18;
+    /** GEA5 cipher */
+    public static final int SECURITY_ALGORITHM_GEA5 = 19;
+    /* 3G PS/CS services (3GPP TS 33.102) */
+    /** UEA0 - null cipher */
+    public static final int SECURITY_ALGORITHM_UEA0 = 29;
+    /** UEA1 cipher */
+    public static final int SECURITY_ALGORITHM_UEA1 = 30;
+    /** UEA2 cipher */
+    public static final int SECURITY_ALGORITHM_UEA2 = 31;
+    /* 4G PS services & 5G NSA (3GPP TS 33.401) */
+    /** EEA0 - null cipher */
+    public static final int SECURITY_ALGORITHM_EEA0 = 41;
+    /** EEA1 */
+    public static final int SECURITY_ALGORITHM_EEA1 = 42;
+    /** EEA2 */
+    public static final int SECURITY_ALGORITHM_EEA2 = 43;
+    /** EEA3 */
+    public static final int SECURITY_ALGORITHM_EEA3 = 44;
+    /* 5G PS services (3GPP TS 33.401 for 5G NSA and 3GPP TS 33.501 for 5G SA) */
+    /** NEA0 - the null cipher */
+    public static final int SECURITY_ALGORITHM_NEA0 = 55;
+    /** NEA1 */
+    public static final int SECURITY_ALGORITHM_NEA1 = 56;
+    /** NEA2 */
+    public static final int SECURITY_ALGORITHM_NEA2 = 57;
+    /** NEA3 */
+    public static final int SECURITY_ALGORITHM_NEA3 = 58;
+    /* IMS and SIP layer security (See 3GPP TS 33.203) */
+    /** No IPsec config */
+    public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66;
+    /** No IMS security, recommended to use SIP_NO_IPSEC_CONFIG and SIP_NULL instead */
+    public static final int SECURITY_ALGORITHM_IMS_NULL = 67;
+    /* IPSEC is present */
+    /** SIP security is not enabled */
+    public static final int SECURITY_ALGORITHM_SIP_NULL = 68;
+    /** AES GCM mode */
+    public static final int SECURITY_ALGORITHM_AES_GCM = 69;
+    /** AES GMAC mode */
+    public static final int SECURITY_ALGORITHM_AES_GMAC = 70;
+    /** AES CBC mode */
+    public static final int SECURITY_ALGORITHM_AES_CBC = 71;
+    /** DES EDE3 CBC mode */
+    public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72;
+    /** AES EDE3 CBC mode */
+    public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73;
+    /** HMAC SHA1 96 */
+    public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74;
+    /** HMAC MD5 96 */
+    public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75;
+    /* RTP and SRTP (see 3GPP TS 33.328) */
+    /** RTP only, SRTP is not being used */
+    public static final int SECURITY_ALGORITHM_RTP = 85;
+    /* When SRTP is available and used */
+    /** SRTP with null ciphering */
+    public static final int SECURITY_ALGORITHM_SRTP_NULL = 86;
+    /** SRTP with AES counter mode */
+    public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87;
+    /** SRTP with AES F8 mode */
+    public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88;
+    /** SRTP with HMAC SHA1 */
+    public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89;
+    /* Ciphers for ePDG (3GPP TS 33.402) */
+    /** ePDG encryption - AES GCM mode */
+    public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99;
+    /** ePDG encryption - AES GCM CBC mode */
+    public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100;
+    /** ePDG authentication - HMAC SHA1 256 128 */
+    public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101;
+    /** Unknown */
+    public static final int SECURITY_ALGORITHM_UNKNOWN = 113;
+    /** Other */
+    public static final int SECURITY_ALGORITHM_OTHER = 114;
+    /** Proprietary algorithms */
+    public static final int SECURITY_ALGORITHM_ORYX = 124;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {SECURITY_ALGORITHM_A50, SECURITY_ALGORITHM_A51,
+            SECURITY_ALGORITHM_A52, SECURITY_ALGORITHM_A53,
+            SECURITY_ALGORITHM_A54, SECURITY_ALGORITHM_GEA0, SECURITY_ALGORITHM_GEA1,
+            SECURITY_ALGORITHM_GEA2, SECURITY_ALGORITHM_GEA3, SECURITY_ALGORITHM_GEA4,
+            SECURITY_ALGORITHM_GEA5, SECURITY_ALGORITHM_UEA0, SECURITY_ALGORITHM_UEA1,
+            SECURITY_ALGORITHM_UEA2, SECURITY_ALGORITHM_EEA0, SECURITY_ALGORITHM_EEA1,
+            SECURITY_ALGORITHM_EEA2, SECURITY_ALGORITHM_EEA3, SECURITY_ALGORITHM_NEA0,
+            SECURITY_ALGORITHM_NEA1, SECURITY_ALGORITHM_NEA2, SECURITY_ALGORITHM_NEA3,
+            SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG, SECURITY_ALGORITHM_IMS_NULL,
+            SECURITY_ALGORITHM_SIP_NULL, SECURITY_ALGORITHM_AES_GCM,
+            SECURITY_ALGORITHM_AES_GMAC, SECURITY_ALGORITHM_AES_CBC,
+            SECURITY_ALGORITHM_DES_EDE3_CBC, SECURITY_ALGORITHM_AES_EDE3_CBC,
+            SECURITY_ALGORITHM_HMAC_SHA1_96, SECURITY_ALGORITHM_HMAC_MD5_96,
+            SECURITY_ALGORITHM_RTP, SECURITY_ALGORITHM_SRTP_NULL,
+            SECURITY_ALGORITHM_SRTP_AES_COUNTER, SECURITY_ALGORITHM_SRTP_AES_F8,
+            SECURITY_ALGORITHM_SRTP_HMAC_SHA1, SECURITY_ALGORITHM_ENCR_AES_GCM_16,
+            SECURITY_ALGORITHM_ENCR_AES_CBC, SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128,
+            SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_OTHER, SECURITY_ALGORITHM_ORYX})
+    public @interface SecurityAlgorithm {
+    }
+
     private @ConnectionEvent int mConnectionEvent;
     private @SecurityAlgorithm int mEncryption;
     private @SecurityAlgorithm int mIntegrity;
     private boolean mIsUnprotectedEmergency;
 
+    /**
+     * Constructor for new SecurityAlgorithmUpdate instances.
+     *
+     * @hide
+     */
+    @TestApi
     public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent,
             @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity,
             boolean isUnprotectedEmergency) {
@@ -52,18 +232,30 @@
         readFromParcel(in);
     }
 
+    /**
+     * @return the connection event.
+     */
     public @ConnectionEvent int getConnectionEvent() {
         return mConnectionEvent;
     }
 
+    /**
+     * @return the encryption algorithm.
+     */
     public @SecurityAlgorithm int getEncryption() {
         return mEncryption;
     }
 
+    /**
+     * @return the integrity algorithm.
+     */
     public @SecurityAlgorithm int getIntegrity() {
         return mIntegrity;
     }
 
+    /**
+     * @return if the security algorithm update is associated with an unprotected emergency call.
+     */
     public boolean isUnprotectedEmergency() {
         return mIsUnprotectedEmergency;
     }
@@ -74,7 +266,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(mConnectionEvent);
         out.writeInt(mEncryption);
         out.writeInt(mIntegrity);
@@ -88,7 +280,7 @@
         mIsUnprotectedEmergency = in.readBoolean();
     }
 
-    public static final Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR =
+    public static final @NonNull Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR =
             new Parcelable.Creator<SecurityAlgorithmUpdate>() {
                 public SecurityAlgorithmUpdate createFromParcel(Parcel in) {
                     return new SecurityAlgorithmUpdate(in);
@@ -121,103 +313,4 @@
     public int hashCode() {
         return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency);
     }
-
-    public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0;
-    public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1;
-    public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2;
-    public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3;
-    public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4;
-    public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5;
-    public static final int CONNECTION_EVENT_VOLTE_SIP = 6;
-    public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7;
-    public static final int CONNECTION_EVENT_VOLTE_RTP = 8;
-    public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9;
-    public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10;
-    public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11;
-    public static final int CONNECTION_EVENT_VONR_SIP = 12;
-    public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13;
-    public static final int CONNECTION_EVENT_VONR_RTP = 14;
-    public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {CONNECTION_EVENT_CS_SIGNALLING_GSM,
-            CONNECTION_EVENT_PS_SIGNALLING_GPRS, CONNECTION_EVENT_CS_SIGNALLING_3G,
-            CONNECTION_EVENT_PS_SIGNALLING_3G, CONNECTION_EVENT_NAS_SIGNALLING_LTE,
-            CONNECTION_EVENT_AS_SIGNALLING_LTE, CONNECTION_EVENT_VOLTE_SIP,
-            CONNECTION_EVENT_VOLTE_SIP_SOS, CONNECTION_EVENT_VOLTE_RTP,
-            CONNECTION_EVENT_VOLTE_RTP_SOS, CONNECTION_EVENT_NAS_SIGNALLING_5G,
-            CONNECTION_EVENT_AS_SIGNALLING_5G, CONNECTION_EVENT_VONR_SIP,
-            CONNECTION_EVENT_VONR_SIP_SOS, CONNECTION_EVENT_VONR_RTP,
-            CONNECTION_EVENT_VONR_RTP_SOS})
-    public @interface ConnectionEvent {
-    }
-
-    public static final int SECURITY_ALGORITHM_A50 = 0;
-    public static final int SECURITY_ALGORITHM_A51 = 1;
-    public static final int SECURITY_ALGORITHM_A52 = 2;
-    public static final int SECURITY_ALGORITHM_A53 = 3;
-    public static final int SECURITY_ALGORITHM_A54 = 4;
-    public static final int SECURITY_ALGORITHM_GEA0 = 14;
-    public static final int SECURITY_ALGORITHM_GEA1 = 15;
-    public static final int SECURITY_ALGORITHM_GEA2 = 16;
-    public static final int SECURITY_ALGORITHM_GEA3 = 17;
-    public static final int SECURITY_ALGORITHM_GEA4 = 18;
-    public static final int SECURITY_ALGORITHM_GEA5 = 19;
-    public static final int SECURITY_ALGORITHM_UEA0 = 29;
-    public static final int SECURITY_ALGORITHM_UEA1 = 30;
-    public static final int SECURITY_ALGORITHM_UEA2 = 31;
-    public static final int SECURITY_ALGORITHM_EEA0 = 41;
-    public static final int SECURITY_ALGORITHM_EEA1 = 42;
-    public static final int SECURITY_ALGORITHM_EEA2 = 43;
-    public static final int SECURITY_ALGORITHM_EEA3 = 44;
-    public static final int SECURITY_ALGORITHM_NEA0 = 55;
-    public static final int SECURITY_ALGORITHM_NEA1 = 56;
-    public static final int SECURITY_ALGORITHM_NEA2 = 57;
-    public static final int SECURITY_ALGORITHM_NEA3 = 58;
-    public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66;
-    public static final int SECURITY_ALGORITHM_IMS_NULL = 67;
-    public static final int SECURITY_ALGORITHM_SIP_NULL = 68;
-    public static final int SECURITY_ALGORITHM_AES_GCM = 69;
-    public static final int SECURITY_ALGORITHM_AES_GMAC = 70;
-    public static final int SECURITY_ALGORITHM_AES_CBC = 71;
-    public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72;
-    public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73;
-    public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74;
-    public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75;
-    public static final int SECURITY_ALGORITHM_RTP = 85;
-    public static final int SECURITY_ALGORITHM_SRTP_NULL = 86;
-    public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87;
-    public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88;
-    public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89;
-    public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99;
-    public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100;
-    public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101;
-    public static final int SECURITY_ALGORITHM_UNKNOWN = 113;
-    public static final int SECURITY_ALGORITHM_OTHER = 114;
-    public static final int SECURITY_ALGORITHM_ORYX = 124;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"CONNECTION_EVENT_"}, value = {SECURITY_ALGORITHM_A50, SECURITY_ALGORITHM_A51,
-            SECURITY_ALGORITHM_A52, SECURITY_ALGORITHM_A53,
-            SECURITY_ALGORITHM_A54, SECURITY_ALGORITHM_GEA0, SECURITY_ALGORITHM_GEA1,
-            SECURITY_ALGORITHM_GEA2, SECURITY_ALGORITHM_GEA3, SECURITY_ALGORITHM_GEA4,
-            SECURITY_ALGORITHM_GEA5, SECURITY_ALGORITHM_UEA0, SECURITY_ALGORITHM_UEA1,
-            SECURITY_ALGORITHM_UEA2, SECURITY_ALGORITHM_EEA0, SECURITY_ALGORITHM_EEA1,
-            SECURITY_ALGORITHM_EEA2, SECURITY_ALGORITHM_EEA3, SECURITY_ALGORITHM_NEA0,
-            SECURITY_ALGORITHM_NEA1, SECURITY_ALGORITHM_NEA2, SECURITY_ALGORITHM_NEA3,
-            SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG, SECURITY_ALGORITHM_IMS_NULL,
-            SECURITY_ALGORITHM_SIP_NULL, SECURITY_ALGORITHM_AES_GCM,
-            SECURITY_ALGORITHM_AES_GMAC, SECURITY_ALGORITHM_AES_CBC,
-            SECURITY_ALGORITHM_DES_EDE3_CBC, SECURITY_ALGORITHM_AES_EDE3_CBC,
-            SECURITY_ALGORITHM_HMAC_SHA1_96, SECURITY_ALGORITHM_HMAC_MD5_96,
-            SECURITY_ALGORITHM_RTP, SECURITY_ALGORITHM_SRTP_NULL,
-            SECURITY_ALGORITHM_SRTP_AES_COUNTER, SECURITY_ALGORITHM_SRTP_AES_F8,
-            SECURITY_ALGORITHM_SRTP_HMAC_SHA1, SECURITY_ALGORITHM_ENCR_AES_GCM_16,
-            SECURITY_ALGORITHM_ENCR_AES_CBC, SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128,
-            SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_OTHER, SECURITY_ALGORITHM_ORYX})
-    public @interface SecurityAlgorithm {
-    }
-
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 887b798..23203ed 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -281,6 +281,14 @@
             "satellite_access_configuration";
 
     /**
+     * Bundle key to get the response from
+     * {@link #requestSelectedNbIotSatelliteSubscriptionId(Executor, OutcomeReceiver)}.
+     * @hide
+     */
+    public static final String KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID =
+            "selected_nb_iot_satellite_subscription_id";
+
+    /**
      * The request was successfully processed.
      * @hide
      */
@@ -531,6 +539,12 @@
     @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
     public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29;
 
+    /**
+     * There is no valid satellite subscription selected.
+     * @hide
+     */
+    public static final int SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION = 30;
+
     /** @hide */
     @IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
             SATELLITE_RESULT_SUCCESS,
@@ -562,7 +576,8 @@
             SATELLITE_RESULT_LOCATION_NOT_AVAILABLE,
             SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS,
             SATELLITE_RESULT_DISABLE_IN_PROGRESS,
-            SATELLITE_RESULT_ENABLE_IN_PROGRESS
+            SATELLITE_RESULT_ENABLE_IN_PROGRESS,
+            SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SatelliteResult {}
@@ -2464,6 +2479,68 @@
     }
 
     /**
+     * Request to get the currently selected satellite subscription id as an {@link Integer}.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback object to which the result will be delivered.
+     *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+     *                 will return the time after which the satellite will be visible.
+     *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void requestSelectedNbIotSatelliteSubscriptionId(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                ResultReceiver receiver = new ResultReceiver(null) {
+                    @Override
+                    protected void onReceiveResult(int resultCode, Bundle resultData) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                            if (resultData
+                                    .containsKey(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID)) {
+                                int selectedSatelliteSubscriptionId =
+                                        resultData
+                                            .getInt(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID);
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onResult(selectedSatelliteSubscriptionId)));
+                            } else {
+                                loge(
+                                    "KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID does not exist."
+                                    );
+                                executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
+                            }
+                        } else {
+                            executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+                                    callback.onError(new SatelliteException(resultCode))));
+                        }
+                    }
+                };
+                telephony.requestSelectedNbIotSatelliteSubscriptionId(receiver);
+            } else {
+                loge("requestSelectedNbIotSatelliteSubscriptionId() invalid telephony");
+                executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+                        new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+            }
+        } catch (RemoteException ex) {
+            loge("requestSelectedNbIotSatelliteSubscriptionId() RemoteException: " + ex);
+            executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+                    new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+        }
+    }
+
+    /**
      * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
      * In demo mode, framework will send datagram to modem only when device is aligned with
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a584273..d22e9fa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3018,6 +3018,17 @@
             + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
     void requestTimeForNextSatelliteVisibility(in ResultReceiver receiver);
 
+
+     /**
+     * Request to get the currently selected satellite subscription id.
+     *
+     * @param receiver Result receiver to get the error code of the request and the currently
+     *                 selected satellite subscription id.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void requestSelectedNbIotSatelliteSubscriptionId(in ResultReceiver receiver);
+
     /**
      * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index 8f4bccc..af6ee3d 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -24,6 +24,7 @@
 import android.content.IContentProvider;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.util.Log;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -53,6 +54,7 @@
  * </div>
  */
 public class MockContentResolver extends ContentResolver {
+    private static final String TAG = "MockContentResolver";
     Map<String, ContentProvider> mProviders;
 
     /**
@@ -105,6 +107,7 @@
         if (provider != null) {
             return provider.getIContentProvider();
         } else {
+            Log.w(TAG, "Provider does not exist: " + name);
             return null;
         }
     }
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 9f5e6d1..6432827 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(
+    private fun enterDesktopModeWithDrag(
         wmHelper: WindowManagerStateHelper,
         device: UiDevice,
         motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH)
     ) {
-        innerHelper.launchViaIntent(wmHelper)
         dragToDesktop(
             wmHelper = wmHelper,
             device = device,
@@ -139,14 +155,35 @@
             ?: error("Unable to find resource $MINIMIZE_BUTTON_VIEW\n")
     }
 
-    fun minimizeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice) {
+    fun minimizeDesktopApp(wmHelper: WindowManagerStateHelper, device: UiDevice, isPip: Boolean = false) {
         val caption = getCaptionForTheApp(wmHelper, device)
         val minimizeButton = getMinimizeButtonForTheApp(caption)
         minimizeButton.click()
         wmHelper
             .StateSyncBuilder()
             .withAppTransitionIdle()
-            .withWindowSurfaceDisappeared(innerHelper)
+            .apply {
+                if (isPip) withPipShown() else withWindowSurfaceDisappeared(innerHelper)
+            }
+            .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()
     }
 
@@ -415,6 +452,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
@@ -427,6 +468,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/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/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;
     }