Merge "Add debug logs for private space auto-lock" into main
diff --git a/DREAM_MANAGER_OWNERS b/DREAM_MANAGER_OWNERS
new file mode 100644
index 0000000..48bde60
--- /dev/null
+++ b/DREAM_MANAGER_OWNERS
@@ -0,0 +1 @@
+brycelee@google.com
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 74b34fb..412f2b7 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -104,6 +104,18 @@
     ],
 }
 
+genrule {
+    name: "framework-minus-apex.ravenwood.keep_all",
+    defaults: ["ravenwood-internal-only-visibility-genrule"],
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-minus-apex.ravenwood-base{hoststubgen_keep_all.txt}",
+    ],
+    out: [
+        "hoststubgen_framework-minus-apex_keep_all.txt",
+    ],
+}
+
 java_library {
     name: "services.core-for-hoststubgen",
     installable: false, // host only jar.
@@ -189,6 +201,18 @@
     ],
 }
 
+genrule {
+    name: "services.core.ravenwood.keep_all",
+    defaults: ["ravenwood-internal-only-visibility-genrule"],
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":services.core.ravenwood-base{hoststubgen_keep_all.txt}",
+    ],
+    out: [
+        "hoststubgen_services.core_keep_all.txt",
+    ],
+}
+
 java_library {
     name: "services.core.ravenwood-jarjar",
     installable: false,
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index ef6982e..4ac40a1 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
+import android.annotation.FlaggedApi;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
@@ -30,6 +31,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.DreamService;
+import android.service.dreams.Flags;
 import android.service.dreams.IDreamManager;
 
 /**
@@ -217,4 +219,19 @@
         }
         return false;
     }
+
+    /**
+     * Sets whether the dream is obscured by something.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED)
+    @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+    public void setDreamIsObscured(boolean isObscured) {
+        try {
+            mService.setDreamIsObscured(isObscured);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 97c2e43..2e38c06 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -60,6 +60,9 @@
 # ComponentCaller
 per-file ComponentCaller.java = file:COMPONENT_CALLER_OWNERS
 
+# DreamManager
+per-file DreamManager.java = file:/DREAM_MANAGER_OWNERS
+
 # GrammaticalInflectionManager
 per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS
 per-file grammatical_inflection_manager.aconfig = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index d340f3f..3f2ef84 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -732,6 +732,10 @@
 
     /**
      * Get statically configured sensor properties.
+     * @deprecated Generally unsafe to use, use
+     * {@link FaceManager#addAuthenticatorsRegisteredCallback} API instead.
+     * In most cases this method will work as expected, but during early boot up, it will be
+     * null/empty and there is no way for the caller to know when it's actual value is ready.
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 25bfb2a..2ded615 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1189,6 +1189,10 @@
 
     /**
      * Get statically configured sensor properties.
+     * @deprecated Generally unsafe to use, use
+     * {@link FingerprintManager#addAuthenticatorsRegisteredCallback} API instead.
+     * In most cases this method will work as expected, but during early boot up, it will be
+     * null/empty and there is no way for the caller to know when it's actual value is ready.
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 5f6bdbf..38ab590 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,7 +18,7 @@
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.service.dreams.Flags.dreamHandlesConfirmKeys;
-import static android.service.dreams.Flags.dreamTracksFocus;
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
 
 import android.annotation.FlaggedApi;
 import android.annotation.IdRes;
@@ -571,15 +571,6 @@
     /** {@inheritDoc} */
     @Override
     public void onWindowFocusChanged(boolean hasFocus) {
-        if (!dreamTracksFocus()) {
-            return;
-        }
-
-        try {
-            mDreamManager.onDreamFocusChanged(hasFocus);
-        } catch (RemoteException ex) {
-            // system server died
-        }
     }
 
     /** {@inheritDoc} */
@@ -1737,7 +1728,7 @@
 
         @Override
         public void comeToFront() {
-            if (!dreamTracksFocus()) {
+            if (!dreamHandlesBeingObscured()) {
                 return;
             }
 
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 85f0368..cf98bfe0 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -48,5 +48,6 @@
     void setSystemDreamComponent(in ComponentName componentName);
     void registerDreamOverlayService(in ComponentName componentName);
     void startDreamActivity(in Intent intent);
-    void onDreamFocusChanged(in boolean hasFocus);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)")
+    oneway void setDreamIsObscured(in boolean isObscured);
 }
diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig
index a42eaff..54d950c 100644
--- a/core/java/android/service/dreams/flags.aconfig
+++ b/core/java/android/service/dreams/flags.aconfig
@@ -39,8 +39,11 @@
 }
 
 flag {
-  name: "dream_tracks_focus"
+  name: "dream_handles_being_obscured"
   namespace: "communal"
-  description: "This flag enables the ability for dreams to track whether or not they have focus"
-  bug: "331798001"
+  description: "This flag enables the ability for dreams to handle being obscured"
+  bug: "337302237"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d174bef..9589785 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1025,7 +1025,8 @@
             mWallpaperDimAmount = (!mShouldDimByDefault) ? mCustomDimAmount
                     : Math.max(mDefaultDimAmount, mCustomDimAmount);
 
-            if (!ENABLE_WALLPAPER_DIMMING || mBbqSurfaceControl == null
+            if (!ENABLE_WALLPAPER_DIMMING
+                    || mBbqSurfaceControl == null || !mBbqSurfaceControl.isValid()
                     || mWallpaperDimAmount == mPreviousWallpaperDimAmount) {
                 return;
             }
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index bf2fdda..acef609 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -330,7 +330,7 @@
         InputDeviceInfo info = InputDeviceInfo();
         info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(),
                         "keyboard " + std::to_string(keyboardId), true, false,
-                        ui::ADISPLAY_ID_DEFAULT);
+                        ui::LogicalDisplayId::DEFAULT);
         info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
         info.setKeyCharacterMap(*charMap);
 
diff --git a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
index 7c45c20..c692967 100644
--- a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 1 bar. move to higher ground. -->
         <path
             android:name="ic_signal_cellular_1_4_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H11 V20 H6 z" />
+            android:pathData="M0,0 H11 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
index 02b646d..b01c269 100644
--- a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 1 bar. might have to call you back. -->
         <path
             android:name="ic_signal_cellular_1_5_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H12 V20 H6 z" />
+            android:pathData="M0,0 H12 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
index 514d169..982623d 100644
--- a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 2 bars. 2 out of 4 ain't bad. -->
         <path
             android:name="ic_signal_cellular_2_4_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H14 V20 H6 z" />
+            android:pathData="M0,0 H14 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
index a97f771..75daadd 100644
--- a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml
@@ -23,11 +23,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 2 bars. hanging in there. -->
         <path
             android:name="ic_signal_cellular_2_5_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H14 V20 H6 z" />
+            android:pathData="M0,0 H14 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
index 1bacf4a..4e4bea3 100644
--- a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 3 bars. quite nice. -->
         <path
             android:name="ic_signal_cellular_3_4_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H17 V20 H6 z" />
+            android:pathData="M0,0 H17 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
index 2789d3e..9a98c29 100644
--- a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 3 bars. not great, not terrible. -->
         <path
             android:name="ic_signal_cellular_3_5_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H16 V20 H6 z" />
+            android:pathData="M0,0 H16 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
index 8286dbb..2a37d01 100644
--- a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
+++ b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml
@@ -22,11 +22,11 @@
     <path
         android:fillColor="@android:color/white"
         android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
-    <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z">
+    <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z">
         <!-- 4 bars. extremely respectable. -->
         <path
             android:name="ic_signal_cellular_4_5_bar"
             android:fillColor="@android:color/white"
-            android:pathData="M6,0 H18 V20 H6 z" />
+            android:pathData="M0,0 H18 V24 H0 z" />
     </clip-path>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 37d39a7..5fa13ba 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1346,6 +1346,51 @@
         <attr name="materialColorTertiary" format="color"/>
         <!-- The error color for the app, intended to draw attention to error conditions. @hide -->
         <attr name="materialColorError" format="color"/>
+
+        <!-- System Custom Tokens-->
+        <!-- @hide -->
+        <attr name="customColorWidgetBackground" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorClockHour" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorClockMinute" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorClockSecond" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorThemeApp" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorOnThemeApp" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorThemeAppRing" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorOnThemeAppRing" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorBrandA" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorBrandB" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorBrandC" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorBrandD" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorUnderSurface" format="color"/>
+        <!-- @hide -->
+        <attr name="customColorShadeActive" 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"/>
+        <!-- @hide -->
+        <attr name="customColorOverviewBackground" format="color"/>
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index e671919..5e039b5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -581,6 +581,51 @@
     <color name="system_on_tertiary_fixed">#FFFFFF</color>
     <color name="system_on_tertiary_fixed_variant">#FFFFFF</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">#1D2435</color>
+    <color name="system_clock_minute_light">#20386A</color>
+    <color name="system_clock_second_light">#000000</color>
+    <color name="system_theme_app_light">#2F4578</color>
+    <color name="system_on_theme_app_light">#D6DFFF</color>
+    <color name="system_theme_app_ring_light">#94AAE4</color>
+    <color name="system_on_theme_app_ring_light">#FDD7FA</color>
+    <color name="system_brand_a_light">#3A5084</color>
+    <color name="system_brand_b_light">#6E7488</color>
+    <color name="system_brand_c_light">#6076AC</color>
+    <color name="system_brand_d_light">#8C6D8C</color>
+    <color name="system_under_surface_light">#000000</color>
+    <color name="system_shade_active_light">#D9E2FF</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_overview_background_light">#50525A</color>
+    <color name="system_widget_background_dark">#152E60</color>
+    <color name="system_clock_hour_dark">#9AA0B6</color>
+    <color name="system_clock_minute_dark">#D8E1FF</color>
+    <color name="system_clock_second_dark">#FFFFFF</color>
+    <color name="system_theme_app_dark">#D9E2FF</color>
+    <color name="system_on_theme_app_dark">#304679</color>
+    <color name="system_theme_app_ring_dark">#94AAE4</color>
+    <color name="system_on_theme_app_ring_dark">#E0BBDD</color>
+    <color name="system_brand_a_dark">#90A6DF</color>
+    <color name="system_brand_b_dark">#A4ABC1</color>
+    <color name="system_brand_c_dark">#7A90C8</color>
+    <color name="system_brand_d_dark">#A886A6</color>
+    <color name="system_under_surface_dark">#000000</color>
+    <color name="system_shade_active_dark">#D9E2FF</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_overview_background_dark">#C5C6D0</color>
+
     <!-- Accessibility shortcut icon background color -->
     <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
     <color name="accessibility_magnification_background">#F50D60</color>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae79a4c..d004b05 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -5292,6 +5292,71 @@
   <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="customColorOnThemeAppRing" 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"/>
+
+  <java-symbol name="system_widget_background_light" type="color"/>
+  <java-symbol name="system_clock_hour_light" type="color"/>
+  <java-symbol name="system_clock_minute_light" type="color"/>
+  <java-symbol name="system_clock_second_light" type="color"/>
+  <java-symbol name="system_theme_app_light" type="color"/>
+  <java-symbol name="system_on_theme_app_light" type="color"/>
+  <java-symbol name="system_theme_app_ring_light" type="color"/>
+  <java-symbol name="system_on_theme_app_ring_light" type="color"/>
+  <java-symbol name="system_brand_a_light" type="color"/>
+  <java-symbol name="system_brand_b_light" type="color"/>
+  <java-symbol name="system_brand_c_light" type="color"/>
+  <java-symbol name="system_brand_d_light" type="color"/>
+  <java-symbol name="system_under_surface_light" type="color"/>
+  <java-symbol name="system_shade_active_light" type="color"/>
+  <java-symbol name="system_on_shade_active_light" type="color"/>
+  <java-symbol name="system_on_shade_active_variant_light" type="color"/>
+  <java-symbol name="system_shade_inactive_light" type="color"/>
+  <java-symbol name="system_on_shade_inactive_light" type="color"/>
+  <java-symbol name="system_on_shade_inactive_variant_light" type="color"/>
+  <java-symbol name="system_shade_disabled_light" type="color"/>
+  <java-symbol name="system_overview_background_light" type="color"/>
+  <java-symbol name="system_widget_background_dark" type="color"/>
+  <java-symbol name="system_clock_hour_dark" type="color"/>
+  <java-symbol name="system_clock_minute_dark" type="color"/>
+  <java-symbol name="system_clock_second_dark" type="color"/>
+  <java-symbol name="system_theme_app_dark" type="color"/>
+  <java-symbol name="system_on_theme_app_dark" type="color"/>
+  <java-symbol name="system_theme_app_ring_dark" type="color"/>
+  <java-symbol name="system_on_theme_app_ring_dark" type="color"/>
+  <java-symbol name="system_brand_a_dark" type="color"/>
+  <java-symbol name="system_brand_b_dark" type="color"/>
+  <java-symbol name="system_brand_c_dark" type="color"/>
+  <java-symbol name="system_brand_d_dark" type="color"/>
+  <java-symbol name="system_under_surface_dark" type="color"/>
+  <java-symbol name="system_shade_active_dark" type="color"/>
+  <java-symbol name="system_on_shade_active_dark" type="color"/>
+  <java-symbol name="system_on_shade_active_variant_dark" type="color"/>
+  <java-symbol name="system_shade_inactive_dark" type="color"/>
+  <java-symbol name="system_on_shade_inactive_dark" type="color"/>
+  <java-symbol name="system_on_shade_inactive_variant_dark" type="color"/>
+  <java-symbol name="system_shade_disabled_dark" type="color"/>
+  <java-symbol name="system_overview_background_dark" type="color"/>
+
   <java-symbol type="attr" name="actionModeUndoDrawable" />
   <java-symbol type="attr" name="actionModeRedoDrawable" />
 
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index ee19144..24d4938 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -284,6 +284,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -380,6 +402,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
@@ -475,6 +519,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -572,6 +638,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -668,6 +756,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -772,6 +882,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -867,6 +999,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -961,6 +1115,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -1056,6 +1232,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -1167,6 +1365,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -1263,6 +1483,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -1357,6 +1599,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -1453,6 +1717,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1548,6 +1834,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -1643,6 +1951,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -1738,6 +2068,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -1833,6 +2185,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
@@ -1928,6 +2302,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Theme for the dialog shown when an app crashes or ANRs. -->
@@ -2028,6 +2424,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -2121,6 +2539,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -2352,6 +2792,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -2447,6 +2909,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -2541,6 +3025,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -2636,6 +3142,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -2733,6 +3261,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -2829,6 +3379,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -2931,6 +3503,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
@@ -3029,6 +3623,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -3126,6 +3742,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -3224,6 +3862,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -3303,6 +3963,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -3382,6 +4064,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
@@ -3480,6 +4184,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -3579,6 +4305,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -3676,6 +4424,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -3772,6 +4542,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -3867,6 +4659,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -3962,6 +4776,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -4055,6 +4891,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
@@ -4156,6 +5014,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light">
@@ -4238,6 +5118,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -4312,6 +5214,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -4407,6 +5331,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog">
@@ -4486,6 +5432,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase">
@@ -4605,6 +5573,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -4702,6 +5692,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
@@ -4825,6 +5837,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <style name="ThemeOverlay.DeviceDefault.Accent.Light">
@@ -4878,6 +5912,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
@@ -4935,6 +5991,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_background_dark</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen">
@@ -4988,6 +6066,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</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="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="customColorOverviewBackground">@color/system_overview_background_light</item>
     </style>
 
     <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
@@ -5052,6 +6152,28 @@
         <item name="materialColorSecondary">@color/system_secondary_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="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</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="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="customColorOverviewBackground">@color/system_overview_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/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS
index a779c00..beb77dc 100644
--- a/core/tests/coretests/src/android/net/OWNERS
+++ b/core/tests/coretests/src/android/net/OWNERS
@@ -1,4 +1,5 @@
 include /services/core/java/com/android/server/net/OWNERS
 
-per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
+per-file SSL*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
 per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
+per-file Uri* = varunshah@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 163a896..5600664 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -646,7 +646,7 @@
 
     private void tryDispatchOnBackCancelled(IOnBackInvokedCallback callback) {
         if (!mOnBackStartDispatched) {
-            Log.e(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
+            Log.d(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
             return;
         }
         if (callback == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 037b1ec..c988c2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 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.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.wm.shell.back
 
 import android.animation.Animator
@@ -34,6 +35,7 @@
 import android.view.SurfaceControl
 import android.view.animation.DecelerateInterpolator
 import android.view.animation.Interpolator
+import android.view.animation.Transformation
 import android.window.BackEvent
 import android.window.BackMotionEvent
 import android.window.BackNavigationInfo
@@ -46,52 +48,45 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.animation.Interpolators
 import com.android.wm.shell.protolog.ShellProtoLogGroup
-import com.android.wm.shell.shared.annotations.ShellMainThread
-import javax.inject.Inject
 import kotlin.math.abs
 import kotlin.math.max
 import kotlin.math.min
 
-/** Class that defines cross-activity animation.  */
-@ShellMainThread
-class CrossActivityBackAnimation @Inject constructor(
+abstract class CrossActivityBackAnimation(
     private val context: Context,
     private val background: BackAnimationBackground,
-    private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+    private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+    protected val transaction: SurfaceControl.Transaction,
+    private val choreographer: Choreographer
 ) : ShellBackAnimation() {
 
-    private val startClosingRect = RectF()
-    private val targetClosingRect = RectF()
-    private val currentClosingRect = RectF()
+    protected val startClosingRect = RectF()
+    protected val targetClosingRect = RectF()
+    protected val currentClosingRect = RectF()
 
-    private val startEnteringRect = RectF()
-    private val targetEnteringRect = RectF()
-    private val currentEnteringRect = RectF()
+    protected val startEnteringRect = RectF()
+    protected val targetEnteringRect = RectF()
+    protected val currentEnteringRect = RectF()
 
-    private val backAnimRect = Rect()
+    protected val backAnimRect = Rect()
     private val cropRect = Rect()
 
     private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
 
-    private val backAnimationRunner = BackAnimationRunner(
-        Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY
-    )
+    private val backAnimationRunner =
+        BackAnimationRunner(Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY)
     private val initialTouchPos = PointF()
     private val transformMatrix = Matrix()
     private val tmpFloat9 = FloatArray(9)
-    private var enteringTarget: RemoteAnimationTarget? = null
-    private var closingTarget: RemoteAnimationTarget? = null
-    private val transaction = SurfaceControl.Transaction()
+    protected var enteringTarget: RemoteAnimationTarget? = null
+    protected var closingTarget: RemoteAnimationTarget? = null
     private var triggerBack = false
     private var finishCallback: IRemoteAnimationFinishedCallback? = null
     private val progressAnimator = BackProgressAnimator()
     private val displayBoundsMargin =
         context.resources.getDimension(R.dimen.cross_task_back_vertical_margin)
-    private val enteringStartOffset =
-        context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
 
     private val gestureInterpolator = Interpolators.BACK_GESTURE
-    private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN
     private val verticalMoveInterpolator: Interpolator = DecelerateInterpolator()
 
     private var scrimLayer: SurfaceControl? = null
@@ -103,13 +98,42 @@
     private var rightLetterboxLayer: SurfaceControl? = null
     private var letterboxColor: Int = 0
 
+    /** Background color to be used during the animation, also see [getBackgroundColor] */
+    protected var customizedBackgroundColor = 0
+
+    /**
+     * Whether the entering target should be shifted vertically with the user gesture in pre-commit
+     */
+    abstract val allowEnteringYShift: Boolean
+
+    /**
+     * Subclasses must set the [startEnteringRect] and [targetEnteringRect] to define the movement
+     * of the enteringTarget during pre-commit phase.
+     */
+    abstract fun preparePreCommitEnteringRectMovement()
+
+    /**
+     * Returns a base transformation to apply to the entering target during pre-commit. The system
+     * will apply the default animation on top of it.
+     */
+    protected open fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation? =
+        null
+
     override fun onConfigurationChanged(newConfiguration: Configuration) {
         cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
     }
 
     override fun getRunner() = backAnimationRunner
 
-    private fun startBackAnimation(backMotionEvent: BackMotionEvent) {
+    private fun getBackgroundColor(): Int =
+        when {
+            customizedBackgroundColor != 0 -> customizedBackgroundColor
+            isLetterboxed -> letterboxColor
+            enteringTarget != null -> enteringTarget!!.taskInfo.taskDescription!!.backgroundColor
+            else -> 0
+        }
+
+    protected open fun startBackAnimation(backMotionEvent: BackMotionEvent) {
         if (enteringTarget == null || closingTarget == null) {
             ProtoLog.d(
                 ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
@@ -122,8 +146,8 @@
 
         transaction.setAnimationTransaction()
         isLetterboxed = closingTarget!!.taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
-        enteringHasSameLetterbox = isLetterboxed &&
-                closingTarget!!.localBounds.equals(enteringTarget!!.localBounds)
+        enteringHasSameLetterbox =
+            isLetterboxed && closingTarget!!.localBounds.equals(enteringTarget!!.localBounds)
 
         if (isLetterboxed && !enteringHasSameLetterbox) {
             // Play animation with letterboxes, if closing and entering target have mismatching
@@ -143,32 +167,27 @@
         targetClosingRect.scaleCentered(MAX_SCALE)
         if (backMotionEvent.swipeEdge != BackEvent.EDGE_RIGHT) {
             targetClosingRect.offset(
-                startClosingRect.right - targetClosingRect.right - displayBoundsMargin, 0f
+                startClosingRect.right - targetClosingRect.right - displayBoundsMargin,
+                0f
             )
         }
 
-        // the entering target starts 96dp to the left of the screen edge...
-        startEnteringRect.set(startClosingRect)
-        startEnteringRect.offset(-enteringStartOffset, 0f)
+        preparePreCommitEnteringRectMovement()
 
-        // ...and gets scaled in sync with the closing target
-        targetEnteringRect.set(startEnteringRect)
-        targetEnteringRect.scaleCentered(MAX_SCALE)
-
-        // Draw background with task background color (or letterbox color).
-        val backgroundColor = if (isLetterboxed) {
-            letterboxColor
-        } else {
-            enteringTarget!!.taskInfo.taskDescription!!.backgroundColor
-        }
         background.ensureBackground(
-            closingTarget!!.windowConfiguration.bounds, backgroundColor, transaction
+            closingTarget!!.windowConfiguration.bounds,
+            getBackgroundColor(),
+            transaction
         )
         ensureScrimLayer()
         if (isLetterboxed && enteringHasSameLetterbox) {
             // crop left and right letterboxes
-            cropRect.set(closingTarget!!.localBounds.left, 0, closingTarget!!.localBounds.right,
-                    closingTarget!!.windowConfiguration.bounds.height())
+            cropRect.set(
+                closingTarget!!.localBounds.left,
+                0,
+                closingTarget!!.localBounds.right,
+                closingTarget!!.windowConfiguration.bounds.height()
+            )
             // and add fake letterbox square surfaces instead
             ensureLetterboxes()
         } else {
@@ -185,8 +204,14 @@
         currentClosingRect.offset(0f, yOffset)
         applyTransform(closingTarget?.leash, currentClosingRect, 1f)
         currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
-        currentEnteringRect.offset(0f, yOffset)
-        applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
+        if (allowEnteringYShift) currentEnteringRect.offset(0f, yOffset)
+        val enteringTransformation = getPreCommitEnteringBaseTransformation(progress)
+        applyTransform(
+            enteringTarget?.leash,
+            currentEnteringRect,
+            enteringTransformation?.alpha ?: 1f,
+            enteringTransformation
+        )
         applyTransaction()
     }
 
@@ -199,30 +224,25 @@
         val deltaYRatio = min(screenHeight / 2f, abs(rawYDelta)) / (screenHeight / 2f)
         val interpolatedYRatio: Float = verticalMoveInterpolator.getInterpolation(deltaYRatio)
         // limit y-shift so surface never passes 8dp screen margin
-        val deltaY = yDirection * interpolatedYRatio * max(
-            0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin
-        )
+        val deltaY =
+            max(0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin) *
+                interpolatedYRatio *
+                yDirection
         return deltaY
     }
 
-    private fun onGestureCommitted() {
-        if (closingTarget?.leash == null || enteringTarget?.leash == null ||
-                !enteringTarget!!.leash.isValid || !closingTarget!!.leash.isValid
+    protected open fun onGestureCommitted() {
+        if (
+            closingTarget?.leash == null ||
+                enteringTarget?.leash == null ||
+                !enteringTarget!!.leash.isValid ||
+                !closingTarget!!.leash.isValid
         ) {
             finishAnimation()
             return
         }
 
-        // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
-        // coordinate of the gesture driven phase. Let's update the start and target rects and kick
-        // off the animator
-        startClosingRect.set(currentClosingRect)
-        startEnteringRect.set(currentEnteringRect)
-        targetEnteringRect.set(backAnimRect)
-        targetClosingRect.set(backAnimRect)
-        targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
-
-        val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION)
+        val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION)
         valueAnimator.addUpdateListener { animation: ValueAnimator ->
             val progress = animation.animatedFraction
             onPostCommitProgress(progress)
@@ -230,27 +250,22 @@
                 background.resetStatusBarCustomization()
             }
         }
-        valueAnimator.addListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator) {
-                background.resetStatusBarCustomization()
-                finishAnimation()
+        valueAnimator.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    background.resetStatusBarCustomization()
+                    finishAnimation()
+                }
             }
-        })
+        )
         valueAnimator.start()
     }
 
-    private fun onPostCommitProgress(linearProgress: Float) {
-        val closingAlpha = max(1f - linearProgress * 2, 0f)
-        val progress = postCommitInterpolator.getInterpolation(linearProgress)
+    protected open fun onPostCommitProgress(linearProgress: Float) {
         scrimLayer?.let { transaction.setAlpha(it, maxScrimAlpha * (1f - linearProgress)) }
-        currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress)
-        applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha)
-        currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
-        applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
-        applyTransaction()
     }
 
-    private fun finishAnimation() {
+    protected open fun finishAnimation() {
         enteringTarget?.let {
             if (it.leash != null && it.leash.isValid) {
                 transaction.setCornerRadius(it.leash, 0f)
@@ -278,47 +293,56 @@
         enteringHasSameLetterbox = false
     }
 
-    private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) {
+    protected fun applyTransform(
+        leash: SurfaceControl?,
+        rect: RectF,
+        alpha: Float,
+        baseTransformation: Transformation? = null
+    ) {
         if (leash == null || !leash.isValid) return
         val scale = rect.width() / backAnimRect.width()
-        transformMatrix.reset()
-        val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) {
-            closingTarget!!.localBounds.left.toFloat()
-        } else {
-            0f
-        }
-        transformMatrix.setScale(scale, scale, scalePivotX, 0f)
-        transformMatrix.postTranslate(rect.left, rect.top)
-        transaction.setAlpha(leash, alpha)
-            .setMatrix(leash, transformMatrix, tmpFloat9)
+        val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() }
+        val scalePivotX =
+            if (isLetterboxed && enteringHasSameLetterbox) {
+                closingTarget!!.localBounds.left.toFloat()
+            } else {
+                0f
+            }
+        matrix.postScale(scale, scale, scalePivotX, 0f)
+        matrix.postTranslate(rect.left, rect.top)
+        transaction
+            .setAlpha(leash, keepMinimumAlpha(alpha))
+            .setMatrix(leash, matrix, tmpFloat9)
             .setCrop(leash, cropRect)
             .setCornerRadius(leash, cornerRadius)
     }
 
-    private fun applyTransaction() {
-        transaction.setFrameTimelineVsync(Choreographer.getInstance().vsyncId)
+    protected fun applyTransaction() {
+        transaction.setFrameTimelineVsync(choreographer.vsyncId)
         transaction.apply()
     }
 
     private fun ensureScrimLayer() {
         if (scrimLayer != null) return
         val isDarkTheme: Boolean = isDarkMode(context)
-        val scrimBuilder = SurfaceControl.Builder()
-            .setName("Cross-Activity back animation scrim")
-            .setCallsite("CrossActivityBackAnimation")
-            .setColorLayer()
-            .setOpaque(false)
-            .setHidden(false)
+        val scrimBuilder =
+            SurfaceControl.Builder()
+                .setName("Cross-Activity back animation scrim")
+                .setCallsite("CrossActivityBackAnimation")
+                .setColorLayer()
+                .setOpaque(false)
+                .setHidden(false)
 
         rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, scrimBuilder)
         scrimLayer = scrimBuilder.build()
         val colorComponents = floatArrayOf(0f, 0f, 0f)
         maxScrimAlpha = if (isDarkTheme) MAX_SCRIM_ALPHA_DARK else MAX_SCRIM_ALPHA_LIGHT
-        val scrimCrop = if (isLetterboxed) {
-            closingTarget!!.windowConfiguration.bounds
-        } else {
-            closingTarget!!.localBounds
-        }
+        val scrimCrop =
+            if (isLetterboxed) {
+                closingTarget!!.windowConfiguration.bounds
+            } else {
+                closingTarget!!.localBounds
+            }
         transaction
             .setColor(scrimLayer, colorComponents)
             .setAlpha(scrimLayer!!, maxScrimAlpha)
@@ -339,21 +363,34 @@
     private fun ensureLetterboxes() {
         closingTarget?.let { t ->
             if (t.localBounds.left != 0 && leftLetterboxLayer == null) {
-                val bounds = Rect(0, t.windowConfiguration.bounds.top, t.localBounds.left,
-                        t.windowConfiguration.bounds.bottom)
+                val bounds =
+                    Rect(
+                        0,
+                        t.windowConfiguration.bounds.top,
+                        t.localBounds.left,
+                        t.windowConfiguration.bounds.bottom
+                    )
                 leftLetterboxLayer = ensureLetterbox(bounds)
             }
-            if (t.localBounds.right != t.windowConfiguration.bounds.right &&
-                    rightLetterboxLayer == null) {
-                val bounds = Rect(t.localBounds.right, t.windowConfiguration.bounds.top,
-                        t.windowConfiguration.bounds.right, t.windowConfiguration.bounds.bottom)
+            if (
+                t.localBounds.right != t.windowConfiguration.bounds.right &&
+                    rightLetterboxLayer == null
+            ) {
+                val bounds =
+                    Rect(
+                        t.localBounds.right,
+                        t.windowConfiguration.bounds.top,
+                        t.windowConfiguration.bounds.right,
+                        t.windowConfiguration.bounds.bottom
+                    )
                 rightLetterboxLayer = ensureLetterbox(bounds)
             }
         }
     }
 
     private fun ensureLetterbox(bounds: Rect): SurfaceControl {
-        val letterboxBuilder = SurfaceControl.Builder()
+        val letterboxBuilder =
+            SurfaceControl.Builder()
                 .setName("Cross-Activity back animation letterbox")
                 .setCallsite("CrossActivityBackAnimation")
                 .setColorLayer()
@@ -362,13 +399,17 @@
 
         rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder)
         val layer = letterboxBuilder.build()
-        val colorComponents = floatArrayOf(Color.red(letterboxColor) / 255f,
-                Color.green(letterboxColor) / 255f, Color.blue(letterboxColor) / 255f)
+        val colorComponents =
+            floatArrayOf(
+                Color.red(letterboxColor) / 255f,
+                Color.green(letterboxColor) / 255f,
+                Color.blue(letterboxColor) / 255f
+            )
         transaction
-                .setColor(layer, colorComponents)
-                .setCrop(layer, bounds)
-                .setRelativeLayer(layer, closingTarget!!.leash, 1)
-                .show(layer)
+            .setColor(layer, colorComponents)
+            .setCrop(layer, bounds)
+            .setRelativeLayer(layer, closingTarget!!.leash, 1)
+            .show(layer)
         return layer
     }
 
@@ -389,8 +430,8 @@
     }
 
     override fun prepareNextAnimation(
-            animationInfo: BackNavigationInfo.CustomAnimationInfo?,
-            letterboxColor: Int
+        animationInfo: BackNavigationInfo.CustomAnimationInfo?,
+        letterboxColor: Int
     ): Boolean {
         this.letterboxColor = letterboxColor
         return false
@@ -415,9 +456,7 @@
         }
 
         override fun onBackCancelled() {
-            progressAnimator.onBackCancelled {
-                finishAnimation()
-            }
+            progressAnimator.onBackCancelled { finishAnimation() }
         }
 
         override fun onBackInvoked() {
@@ -435,7 +474,8 @@
             finishedCallback: IRemoteAnimationFinishedCallback
         ) {
             ProtoLog.d(
-                ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "Start back to activity animation."
+                ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
+                "Start back to activity animation."
             )
             for (a in apps) {
                 when (a.mode) {
@@ -452,23 +492,25 @@
     }
 
     companion object {
-        /** Max scale of the entering/closing window.*/
-        private const val MAX_SCALE = 0.9f
-
-        /** Duration of post animation after gesture committed.  */
-        private const val POST_ANIMATION_DURATION = 300L
-
+        /** Max scale of the closing window. */
+        internal const val MAX_SCALE = 0.9f
         private const val MAX_SCRIM_ALPHA_DARK = 0.8f
         private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f
+        private const val POST_COMMIT_DURATION = 300L
     }
 }
 
+// The target will loose focus when alpha == 0, so keep a minimum value for it.
+private fun keepMinimumAlpha(transAlpha: Float): Float {
+    return max(transAlpha.toDouble(), 0.005).toFloat()
+}
+
 private fun isDarkMode(context: Context): Boolean {
     return context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
-            Configuration.UI_MODE_NIGHT_YES
+        Configuration.UI_MODE_NIGHT_YES
 }
 
-private fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) {
+internal fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) {
     require(!(progress < 0 || progress > 1)) { "Progress value must be between 0 and 1" }
     left = start.left + (target.left - start.left) * progress
     top = start.top + (target.top - start.top) * progress
@@ -476,7 +518,7 @@
     bottom = start.bottom + (target.bottom - start.bottom) * progress
 }
 
-private fun RectF.scaleCentered(
+internal fun RectF.scaleCentered(
     scale: Float,
     pivotX: Float = left + width() / 2,
     pivotY: Float = top + height() / 2
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
new file mode 100644
index 0000000..e6ec2b4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -0,0 +1,256 @@
+/*
+ * 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.back
+
+import android.content.Context
+import android.graphics.Rect
+import android.graphics.RectF
+import android.util.MathUtils
+import android.view.Choreographer
+import android.view.SurfaceControl
+import android.view.animation.Animation
+import android.view.animation.Transformation
+import android.window.BackMotionEvent
+import android.window.BackNavigationInfo
+import com.android.internal.R
+import com.android.internal.policy.TransitionAnimation
+import com.android.internal.protolog.common.ProtoLog
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import javax.inject.Inject
+
+/** Class that handles customized predictive cross activity back animations. */
+@ShellMainThread
+class CustomCrossActivityBackAnimation(
+    context: Context,
+    background: BackAnimationBackground,
+    rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+    transaction: SurfaceControl.Transaction,
+    choreographer: Choreographer,
+    private val customAnimationLoader: CustomAnimationLoader
+) :
+    CrossActivityBackAnimation(
+        context,
+        background,
+        rootTaskDisplayAreaOrganizer,
+        transaction,
+        choreographer
+    ) {
+
+    private var enterAnimation: Animation? = null
+    private var closeAnimation: Animation? = null
+    private val transformation = Transformation()
+    private var gestureProgress = 0f
+
+    override val allowEnteringYShift = false
+
+    @Inject
+    constructor(
+        context: Context,
+        background: BackAnimationBackground,
+        rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+    ) : this(
+        context,
+        background,
+        rootTaskDisplayAreaOrganizer,
+        SurfaceControl.Transaction(),
+        Choreographer.getInstance(),
+        CustomAnimationLoader(
+            TransitionAnimation(context, false /* debug */, "CustomCrossActivityBackAnimation")
+        )
+    )
+
+    override fun preparePreCommitEnteringRectMovement() {
+        // No movement for the entering rect
+        startEnteringRect.set(startClosingRect)
+        targetEnteringRect.set(startClosingRect)
+    }
+
+    override fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation {
+        gestureProgress = progress
+        transformation.clear()
+        enterAnimation!!.getTransformationAt(progress * PRE_COMMIT_MAX_PROGRESS, transformation)
+        return transformation
+    }
+
+    override fun startBackAnimation(backMotionEvent: BackMotionEvent) {
+        super.startBackAnimation(backMotionEvent)
+        if (
+            closeAnimation == null ||
+                enterAnimation == null ||
+                closingTarget == null ||
+                enteringTarget == null
+        ) {
+            ProtoLog.d(
+                ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW,
+                "Enter animation or close animation is null."
+            )
+            return
+        }
+        initializeAnimation(closeAnimation!!, closingTarget!!.localBounds)
+        initializeAnimation(enterAnimation!!, enteringTarget!!.localBounds)
+    }
+
+    override fun onPostCommitProgress(linearProgress: Float) {
+        super.onPostCommitProgress(linearProgress)
+        if (closingTarget == null || enteringTarget == null) return
+
+        // TODO: Should we use the duration from the custom xml spec for the post-commit animation?
+        applyTransform(closingTarget!!.leash, currentClosingRect, linearProgress, closeAnimation!!)
+        val enteringProgress =
+            MathUtils.lerp(gestureProgress * PRE_COMMIT_MAX_PROGRESS, 1f, linearProgress)
+        applyTransform(
+            enteringTarget!!.leash,
+            currentEnteringRect,
+            enteringProgress,
+            enterAnimation!!
+        )
+        applyTransaction()
+    }
+
+    private fun applyTransform(
+        leash: SurfaceControl,
+        rect: RectF,
+        progress: Float,
+        animation: Animation
+    ) {
+        transformation.clear()
+        animation.getTransformationAt(progress, transformation)
+        applyTransform(leash, rect, transformation.alpha, transformation)
+    }
+
+    override fun finishAnimation() {
+        closeAnimation?.reset()
+        closeAnimation = null
+        enterAnimation?.reset()
+        enterAnimation = null
+        transformation.clear()
+        gestureProgress = 0f
+        super.finishAnimation()
+    }
+
+    /** Load customize animation before animation start. */
+    override fun prepareNextAnimation(
+        animationInfo: BackNavigationInfo.CustomAnimationInfo?,
+        letterboxColor: Int
+    ): Boolean {
+        super.prepareNextAnimation(animationInfo, letterboxColor)
+        if (animationInfo == null) return false
+        customAnimationLoader.loadAll(animationInfo)?.let { result ->
+            closeAnimation = result.closeAnimation
+            enterAnimation = result.enterAnimation
+            customizedBackgroundColor = result.backgroundColor
+            return true
+        }
+        return false
+    }
+
+    class AnimationLoadResult {
+        var closeAnimation: Animation? = null
+        var enterAnimation: Animation? = null
+        var backgroundColor = 0
+    }
+
+    companion object {
+        private const val PRE_COMMIT_MAX_PROGRESS = 0.2f
+    }
+}
+
+/** Helper class to load custom animation. */
+class CustomAnimationLoader(private val transitionAnimation: TransitionAnimation) {
+
+    /**
+     * Load both enter and exit animation for the close activity transition. Note that the result is
+     * only valid if the exit animation has set and loaded success. If the entering animation has
+     * not set(i.e. 0), here will load the default entering animation for it.
+     *
+     * @param animationInfo The information of customize animation, which can be set from
+     *   [Activity.overrideActivityTransition] and/or [LayoutParams.windowAnimations]
+     */
+    fun loadAll(
+        animationInfo: BackNavigationInfo.CustomAnimationInfo
+    ): CustomCrossActivityBackAnimation.AnimationLoadResult? {
+        if (animationInfo.packageName.isEmpty()) return null
+        val close = loadAnimation(animationInfo, false) ?: return null
+        val open = loadAnimation(animationInfo, true)
+        val result = CustomCrossActivityBackAnimation.AnimationLoadResult()
+        result.closeAnimation = close
+        result.enterAnimation = open
+        result.backgroundColor = animationInfo.customBackground
+        return result
+    }
+
+    /**
+     * Load enter or exit animation from CustomAnimationInfo
+     *
+     * @param animationInfo The information for customize animation.
+     * @param enterAnimation true when load for enter animation, false for exit animation.
+     * @return Loaded animation.
+     */
+    fun loadAnimation(
+        animationInfo: BackNavigationInfo.CustomAnimationInfo,
+        enterAnimation: Boolean
+    ): Animation? {
+        var a: Animation? = null
+        // Activity#overrideActivityTransition has higher priority than windowAnimations
+        // Try to get animation from Activity#overrideActivityTransition
+        if (
+            enterAnimation && animationInfo.customEnterAnim != 0 ||
+                !enterAnimation && animationInfo.customExitAnim != 0
+        ) {
+            a =
+                transitionAnimation.loadAppTransitionAnimation(
+                    animationInfo.packageName,
+                    if (enterAnimation) animationInfo.customEnterAnim
+                    else animationInfo.customExitAnim
+                )
+        } else if (animationInfo.windowAnimations != 0) {
+            // try to get animation from LayoutParams#windowAnimations
+            a =
+                transitionAnimation.loadAnimationAttr(
+                    animationInfo.packageName,
+                    animationInfo.windowAnimations,
+                    if (enterAnimation) R.styleable.WindowAnimation_activityCloseEnterAnimation
+                    else R.styleable.WindowAnimation_activityCloseExitAnimation,
+                    false /* translucent */
+                )
+        }
+        // Only allow to load default animation for opening target.
+        if (a == null && enterAnimation) {
+            a = loadDefaultOpenAnimation()
+        }
+        if (a != null) {
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a)
+        } else {
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "No custom animation loaded")
+        }
+        return a
+    }
+
+    private fun loadDefaultOpenAnimation(): Animation? {
+        return transitionAnimation.loadDefaultAnimationAttr(
+            R.styleable.WindowAnimation_activityCloseEnterAnimation,
+            false /* translucent */
+        )
+    }
+}
+
+private fun initializeAnimation(animation: Animation, bounds: Rect) {
+    val width = bounds.width()
+    val height = bounds.height()
+    animation.initialize(width, height, width, height)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
deleted file mode 100644
index e27b40e..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static android.view.RemoteAnimationTarget.MODE_OPENING;
-
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.FloatProperty;
-import android.view.Choreographer;
-import android.view.IRemoteAnimationFinishedCallback;
-import android.view.IRemoteAnimationRunner;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.WindowManager.LayoutParams;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Transformation;
-import android.window.BackEvent;
-import android.window.BackMotionEvent;
-import android.window.BackNavigationInfo;
-import android.window.BackProgressAnimator;
-import android.window.IOnBackInvokedCallback;
-
-import com.android.internal.R;
-import com.android.internal.dynamicanimation.animation.SpringAnimation;
-import com.android.internal.dynamicanimation.animation.SpringForce;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.shared.annotations.ShellMainThread;
-
-import javax.inject.Inject;
-
-/** Class that handle customized close activity transition animation. */
-@ShellMainThread
-public class CustomizeActivityAnimation extends ShellBackAnimation {
-    private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
-    private final BackAnimationRunner mBackAnimationRunner;
-    private float mCornerRadius;
-    private final SurfaceControl.Transaction mTransaction;
-    private final BackAnimationBackground mBackground;
-    private RemoteAnimationTarget mEnteringTarget;
-    private RemoteAnimationTarget mClosingTarget;
-    private IRemoteAnimationFinishedCallback mFinishCallback;
-    /** Duration of post animation after gesture committed. */
-    private static final int POST_ANIMATION_DURATION = 250;
-
-    private static final int SCALE_FACTOR = 1000;
-    private final SpringAnimation mProgressSpring;
-    private float mLatestProgress = 0.0f;
-
-    private static final float TARGET_COMMIT_PROGRESS = 0.5f;
-
-    private final float[] mTmpFloat9 = new float[9];
-    private final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
-
-    final CustomAnimationLoader mCustomAnimationLoader;
-    private Animation mEnterAnimation;
-    private Animation mCloseAnimation;
-    private int mNextBackgroundColor;
-    final Transformation mTransformation = new Transformation();
-
-    private final Choreographer mChoreographer;
-    private final Context mContext;
-
-    @Inject
-    public CustomizeActivityAnimation(Context context, BackAnimationBackground background) {
-        this(context, background, new SurfaceControl.Transaction(), null);
-    }
-
-    CustomizeActivityAnimation(Context context, BackAnimationBackground background,
-            SurfaceControl.Transaction transaction, Choreographer choreographer) {
-        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
-        mBackground = background;
-        mBackAnimationRunner = new BackAnimationRunner(
-                new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY);
-        mCustomAnimationLoader = new CustomAnimationLoader(context);
-
-        mProgressSpring = new SpringAnimation(this, ENTER_PROGRESS_PROP);
-        mProgressSpring.setSpring(new SpringForce()
-                .setStiffness(SpringForce.STIFFNESS_MEDIUM)
-                .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY));
-        mTransaction = transaction == null ? new SurfaceControl.Transaction() : transaction;
-        mChoreographer = choreographer != null ? choreographer : Choreographer.getInstance();
-        mContext = context;
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
-    }
-
-    private float getLatestProgress() {
-        return mLatestProgress * SCALE_FACTOR;
-    }
-    private void setLatestProgress(float value) {
-        mLatestProgress = value / SCALE_FACTOR;
-        applyTransformTransaction(mLatestProgress);
-    }
-
-    private static final FloatProperty<CustomizeActivityAnimation> ENTER_PROGRESS_PROP =
-            new FloatProperty<>("enter") {
-                @Override
-                public void setValue(CustomizeActivityAnimation anim, float value) {
-                    anim.setLatestProgress(value);
-                }
-
-                @Override
-                public Float get(CustomizeActivityAnimation object) {
-                    return object.getLatestProgress();
-                }
-            };
-
-    // The target will lose focus when alpha == 0, so keep a minimum value for it.
-    private static float keepMinimumAlpha(float transAlpha) {
-        return Math.max(transAlpha, 0.005f);
-    }
-
-    private static void initializeAnimation(Animation animation, Rect bounds) {
-        final int width = bounds.width();
-        final int height = bounds.height();
-        animation.initialize(width, height, width, height);
-    }
-
-    private void startBackAnimation() {
-        if (mEnteringTarget == null || mClosingTarget == null
-                || mCloseAnimation == null || mEnterAnimation == null) {
-            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Entering target or closing target is null.");
-            return;
-        }
-        initializeAnimation(mCloseAnimation, mClosingTarget.localBounds);
-        initializeAnimation(mEnterAnimation, mEnteringTarget.localBounds);
-
-        // Draw background with task background color.
-        if (mEnteringTarget.taskInfo != null && mEnteringTarget.taskInfo.taskDescription != null) {
-            mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(),
-                    mNextBackgroundColor == Color.TRANSPARENT
-                            ? mEnteringTarget.taskInfo.taskDescription.getBackgroundColor()
-                            : mNextBackgroundColor,
-                    mTransaction);
-        }
-    }
-
-    private void applyTransformTransaction(float progress) {
-        if (mClosingTarget == null || mEnteringTarget == null) {
-            return;
-        }
-        applyTransform(mClosingTarget.leash, progress, mCloseAnimation);
-        applyTransform(mEnteringTarget.leash, progress, mEnterAnimation);
-        mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
-        mTransaction.apply();
-    }
-
-    private void applyTransform(SurfaceControl leash, float progress, Animation animation) {
-        mTransformation.clear();
-        animation.getTransformationAt(progress, mTransformation);
-        mTransaction.setMatrix(leash, mTransformation.getMatrix(), mTmpFloat9);
-        mTransaction.setAlpha(leash, keepMinimumAlpha(mTransformation.getAlpha()));
-        mTransaction.setCornerRadius(leash, mCornerRadius);
-    }
-
-    void finishAnimation() {
-        if (mCloseAnimation != null) {
-            mCloseAnimation.reset();
-            mCloseAnimation = null;
-        }
-        if (mEnterAnimation != null) {
-            mEnterAnimation.reset();
-            mEnterAnimation = null;
-        }
-        if (mEnteringTarget != null) {
-            mEnteringTarget.leash.release();
-            mEnteringTarget = null;
-        }
-        if (mClosingTarget != null) {
-            mClosingTarget.leash.release();
-            mClosingTarget = null;
-        }
-        if (mBackground != null) {
-            mBackground.removeBackground(mTransaction);
-        }
-        mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
-        mTransaction.apply();
-        mTransformation.clear();
-        mLatestProgress = 0;
-        mNextBackgroundColor = Color.TRANSPARENT;
-        if (mFinishCallback != null) {
-            try {
-                mFinishCallback.onAnimationFinished();
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-            mFinishCallback = null;
-        }
-        mProgressSpring.animateToFinalPosition(0);
-        mProgressSpring.skipToEnd();
-    }
-
-    void onGestureProgress(@NonNull BackEvent backEvent) {
-        if (mEnteringTarget == null || mClosingTarget == null
-                || mCloseAnimation == null || mEnterAnimation == null) {
-            return;
-        }
-
-        final float progress = backEvent.getProgress();
-
-        float springProgress = (progress > 0.1f
-                ? mapLinear(progress, 0.1f, 1f, TARGET_COMMIT_PROGRESS, 1f)
-                : mapLinear(progress, 0, 1f, 0f, TARGET_COMMIT_PROGRESS)) * SCALE_FACTOR;
-
-        mProgressSpring.animateToFinalPosition(springProgress);
-    }
-
-    static float mapLinear(float x, float a1, float a2, float b1, float b2) {
-        return b1 + (x - a1) * (b2 - b1) / (a2 - a1);
-    }
-
-    void onGestureCommitted() {
-        if (mEnteringTarget == null || mClosingTarget == null
-                || mCloseAnimation == null || mEnterAnimation == null) {
-            finishAnimation();
-            return;
-        }
-        mProgressSpring.cancel();
-
-        // Enter phase 2 of the animation
-        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(mLatestProgress, 1f)
-                .setDuration(POST_ANIMATION_DURATION);
-        valueAnimator.setInterpolator(mDecelerateInterpolator);
-        valueAnimator.addUpdateListener(animation -> {
-            float progress = (float) animation.getAnimatedValue();
-            applyTransformTransaction(progress);
-        });
-
-        valueAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                finishAnimation();
-            }
-        });
-        valueAnimator.start();
-    }
-
-    /** Load customize animation before animation start. */
-    @Override
-    public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo,
-            int letterboxColor) {
-        if (animationInfo == null) {
-            return false;
-        }
-        final AnimationLoadResult result = mCustomAnimationLoader.loadAll(animationInfo);
-        if (result != null) {
-            mCloseAnimation = result.mCloseAnimation;
-            mEnterAnimation = result.mEnterAnimation;
-            mNextBackgroundColor = result.mBackgroundColor;
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public BackAnimationRunner getRunner() {
-        return mBackAnimationRunner;
-    }
-
-    private final class Callback extends IOnBackInvokedCallback.Default {
-        @Override
-        public void onBackStarted(BackMotionEvent backEvent) {
-            // in case we're still animating an onBackCancelled event, let's remove the finish-
-            // callback from the progress animator to prevent calling finishAnimation() before
-            // restarting a new animation
-            mProgressAnimator.removeOnBackCancelledFinishCallback();
-
-            mProgressAnimator.onBackStarted(backEvent,
-                    CustomizeActivityAnimation.this::onGestureProgress);
-        }
-
-        @Override
-        public void onBackProgressed(@NonNull BackMotionEvent backEvent) {
-            mProgressAnimator.onBackProgressed(backEvent);
-        }
-
-        @Override
-        public void onBackCancelled() {
-            mProgressAnimator.onBackCancelled(CustomizeActivityAnimation.this::finishAnimation);
-        }
-
-        @Override
-        public void onBackInvoked() {
-            mProgressAnimator.reset();
-            onGestureCommitted();
-        }
-    }
-
-    private final class Runner extends IRemoteAnimationRunner.Default {
-        @Override
-        public void onAnimationStart(
-                int transit,
-                RemoteAnimationTarget[] apps,
-                RemoteAnimationTarget[] wallpapers,
-                RemoteAnimationTarget[] nonApps,
-                IRemoteAnimationFinishedCallback finishedCallback) {
-            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to customize animation.");
-            for (RemoteAnimationTarget a : apps) {
-                if (a.mode == MODE_CLOSING) {
-                    mClosingTarget = a;
-                }
-                if (a.mode == MODE_OPENING) {
-                    mEnteringTarget = a;
-                }
-            }
-            if (mCloseAnimation == null || mEnterAnimation == null) {
-                ProtoLog.d(WM_SHELL_BACK_PREVIEW,
-                        "No animation loaded, should choose cross-activity animation?");
-            }
-
-            startBackAnimation();
-            mFinishCallback = finishedCallback;
-        }
-
-        @Override
-        public void onAnimationCancelled() {
-            finishAnimation();
-        }
-    }
-
-
-    static final class AnimationLoadResult {
-        Animation mCloseAnimation;
-        Animation mEnterAnimation;
-        int mBackgroundColor;
-    }
-
-    /**
-     * Helper class to load custom animation.
-     */
-    static class CustomAnimationLoader {
-        final TransitionAnimation mTransitionAnimation;
-
-        CustomAnimationLoader(Context context) {
-            mTransitionAnimation = new TransitionAnimation(
-                    context, false /* debug */, "CustomizeBackAnimation");
-        }
-
-        /**
-         * Load both enter and exit animation for the close activity transition.
-         * Note that the result is only valid if the exit animation has set and loaded success.
-         * If the entering animation has not set(i.e. 0), here will load the default entering
-         * animation for it.
-         *
-         * @param animationInfo The information of customize animation, which can be set from
-         * {@link Activity#overrideActivityTransition} and/or
-         * {@link LayoutParams#windowAnimations}
-         */
-        AnimationLoadResult loadAll(BackNavigationInfo.CustomAnimationInfo animationInfo) {
-            if (animationInfo.getPackageName().isEmpty()) {
-                return null;
-            }
-            final Animation close = loadAnimation(animationInfo, false);
-            if (close == null) {
-                return null;
-            }
-            final Animation open = loadAnimation(animationInfo, true);
-            AnimationLoadResult result = new AnimationLoadResult();
-            result.mCloseAnimation = close;
-            result.mEnterAnimation = open;
-            result.mBackgroundColor = animationInfo.getCustomBackground();
-            return result;
-        }
-
-        /**
-         * Load enter or exit animation from CustomAnimationInfo
-         * @param animationInfo The information for customize animation.
-         * @param enterAnimation true when load for enter animation, false for exit animation.
-         * @return Loaded animation.
-         */
-        @Nullable
-        Animation loadAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo,
-                boolean enterAnimation) {
-            Animation a = null;
-            // Activity#overrideActivityTransition has higher priority than windowAnimations
-            // Try to get animation from Activity#overrideActivityTransition
-            if ((enterAnimation && animationInfo.getCustomEnterAnim() != 0)
-                    || (!enterAnimation && animationInfo.getCustomExitAnim() != 0)) {
-                a = mTransitionAnimation.loadAppTransitionAnimation(
-                        animationInfo.getPackageName(),
-                        enterAnimation ? animationInfo.getCustomEnterAnim()
-                                : animationInfo.getCustomExitAnim());
-            } else if (animationInfo.getWindowAnimations() != 0) {
-                // try to get animation from LayoutParams#windowAnimations
-                a = mTransitionAnimation.loadAnimationAttr(animationInfo.getPackageName(),
-                        animationInfo.getWindowAnimations(), enterAnimation
-                                ? R.styleable.WindowAnimation_activityCloseEnterAnimation
-                                : R.styleable.WindowAnimation_activityCloseExitAnimation,
-                        false /* translucent */);
-            }
-            // Only allow to load default animation for opening target.
-            if (a == null && enterAnimation) {
-                a = loadDefaultOpenAnimation();
-            }
-            if (a != null) {
-                ProtoLog.d(WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a);
-            } else {
-                ProtoLog.e(WM_SHELL_BACK_PREVIEW, "No custom animation loaded");
-            }
-            return a;
-        }
-
-        private Animation loadDefaultOpenAnimation() {
-            return mTransitionAnimation.loadDefaultAnimationAttr(
-                    R.styleable.WindowAnimation_activityCloseEnterAnimation,
-                    false /* translucent */);
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
new file mode 100644
index 0000000..f33c5b9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.back
+
+import android.content.Context
+import android.view.Choreographer
+import android.view.SurfaceControl
+import com.android.wm.shell.R
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.animation.Interpolators
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import javax.inject.Inject
+import kotlin.math.max
+
+/** Class that defines cross-activity animation. */
+@ShellMainThread
+class DefaultCrossActivityBackAnimation
+@Inject
+constructor(
+    context: Context,
+    background: BackAnimationBackground,
+    rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+) :
+    CrossActivityBackAnimation(
+        context,
+        background,
+        rootTaskDisplayAreaOrganizer,
+        SurfaceControl.Transaction(),
+        Choreographer.getInstance()
+    ) {
+
+    private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN
+    private val enteringStartOffset =
+        context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset)
+    override val allowEnteringYShift = true
+
+    override fun preparePreCommitEnteringRectMovement() {
+        // the entering target starts 96dp to the left of the screen edge...
+        startEnteringRect.set(startClosingRect)
+        startEnteringRect.offset(-enteringStartOffset, 0f)
+        // ...and gets scaled in sync with the closing target
+        targetEnteringRect.set(startEnteringRect)
+        targetEnteringRect.scaleCentered(MAX_SCALE)
+    }
+
+    override fun onGestureCommitted() {
+        // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
+        // coordinate of the gesture driven phase. Let's update the start and target rects and kick
+        // off the animator in the superclass
+        startClosingRect.set(currentClosingRect)
+        startEnteringRect.set(currentEnteringRect)
+        targetEnteringRect.set(backAnimRect)
+        targetClosingRect.set(backAnimRect)
+        targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
+        super.onGestureCommitted()
+    }
+
+    override fun onPostCommitProgress(linearProgress: Float) {
+        super.onPostCommitProgress(linearProgress)
+        val closingAlpha = max(1f - linearProgress * 2, 0f)
+        val progress = postCommitInterpolator.getInterpolation(linearProgress)
+        currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress)
+        applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha)
+        currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress)
+        applyTransform(enteringTarget?.leash, currentEnteringRect, 1f)
+        applyTransaction()
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
index 795bc1a..d2895b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.dagger.back;
 
-import com.android.wm.shell.back.CrossActivityBackAnimation;
 import com.android.wm.shell.back.CrossTaskBackAnimation;
-import com.android.wm.shell.back.CustomizeActivityAnimation;
+import com.android.wm.shell.back.CustomCrossActivityBackAnimation;
+import com.android.wm.shell.back.DefaultCrossActivityBackAnimation;
 import com.android.wm.shell.back.ShellBackAnimation;
 import com.android.wm.shell.back.ShellBackAnimationRegistry;
 
@@ -47,7 +47,7 @@
     @Binds
     @ShellBackAnimation.CrossActivity
     ShellBackAnimation bindCrossActivityShellBackAnimation(
-            CrossActivityBackAnimation crossActivityBackAnimation);
+            DefaultCrossActivityBackAnimation defaultCrossActivityBackAnimation);
 
     /** Default cross task back animation */
     @Binds
@@ -59,5 +59,5 @@
     @Binds
     @ShellBackAnimation.CustomizeActivity
     ShellBackAnimation provideCustomizeActivityShellBackAnimation(
-            CustomizeActivityAnimation customizeActivityAnimation);
+            CustomCrossActivityBackAnimation customCrossActivityBackAnimation);
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index bc486c2..984abf8 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -32,7 +32,7 @@
 /**
  * Test launching a new activity from bubble.
  *
- * To run this test: `atest WMShellFlickerTests:MultiBubblesScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:ChangeActiveActivityFromBubbleTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 2a9b107..886b70c 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -35,7 +35,7 @@
 /**
  * Test launching a new activity from bubble.
  *
- * To run this test: `atest WMShellFlickerTests:DismissBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:DragToDismissBubbleScreenTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index 9ef49c1..2ee53f4 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -38,7 +38,7 @@
 /**
  * Test launching a new activity from bubble.
  *
- * To run this test: `atest WMShellFlickerTests:OpenActivityFromBubbleOnLocksreenTest`
+ * To run this test: `atest WMShellFlickerTestsBubbles:OpenActivityFromBubbleOnLocksreenTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index ef7fbfb..463fe0e 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -29,7 +29,7 @@
 /**
  * Test launching a new activity from bubble.
  *
- * To run this test: `atest WMShellFlickerTests:ExpandBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:OpenActivityFromBubbleTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 87224b15..8df5056 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -29,7 +29,7 @@
 /**
  * Test creating a bubble notification
  *
- * To run this test: `atest WMShellFlickerTests:LaunchBubbleScreen`
+ * To run this test: `atest WMShellFlickerTestsBubbles:SendBubbleNotificationTest`
  *
  * Actions:
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
index 17cace0..d485b82 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/DesktopModeFlickerScenarios.kt
@@ -21,6 +21,7 @@
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
 import android.tools.flicker.assertors.assertions.AppWindowHasDesktopModeInitialBoundsAtTheEnd
+import android.tools.flicker.assertors.assertions.AppWindowIsVisibleAlways
 import android.tools.flicker.assertors.assertions.AppWindowOnTopAtEnd
 import android.tools.flicker.assertors.assertions.AppWindowOnTopAtStart
 import android.tools.flicker.assertors.assertions.AppWindowRemainInsideDisplayBounds
@@ -133,9 +134,8 @@
                     }
                 ),
                 assertions =
-                AssertionTemplates.COMMON_ASSERTIONS +
                         listOf(
-                            AppLayerIsVisibleAlways(Components.DESKTOP_MODE_APP),
+                            AppWindowIsVisibleAlways(Components.DESKTOP_MODE_APP),
                             AppWindowOnTopAtEnd(Components.DESKTOP_MODE_APP),
                             AppWindowRemainInsideDisplayBounds(Components.DESKTOP_MODE_APP),
                         ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index f99b4b2..f6f3aa4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -120,7 +120,7 @@
     private TestableContentResolver mContentResolver;
     private TestableLooper mTestableLooper;
 
-    private CrossActivityBackAnimation mCrossActivityBackAnimation;
+    private DefaultCrossActivityBackAnimation mDefaultCrossActivityBackAnimation;
     private CrossTaskBackAnimation mCrossTaskBackAnimation;
     private ShellBackAnimationRegistry mShellBackAnimationRegistry;
 
@@ -135,13 +135,14 @@
                 ANIMATION_ENABLED);
         mTestableLooper = TestableLooper.get(this);
         mShellInit = spy(new ShellInit(mShellExecutor));
-        mCrossActivityBackAnimation = new CrossActivityBackAnimation(mContext, mAnimationBackground,
-                mRootTaskDisplayAreaOrganizer);
+        mDefaultCrossActivityBackAnimation = new DefaultCrossActivityBackAnimation(mContext,
+                mAnimationBackground, mRootTaskDisplayAreaOrganizer);
         mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground);
         mShellBackAnimationRegistry =
-                new ShellBackAnimationRegistry(mCrossActivityBackAnimation, mCrossTaskBackAnimation,
-                        /* dialogCloseAnimation= */ null,
-                        new CustomizeActivityAnimation(mContext, mAnimationBackground),
+                new ShellBackAnimationRegistry(mDefaultCrossActivityBackAnimation,
+                        mCrossTaskBackAnimation, /* dialogCloseAnimation= */ null,
+                        new CustomCrossActivityBackAnimation(mContext, mAnimationBackground,
+                                mRootTaskDisplayAreaOrganizer),
                         /* defaultBackToHomeAnimation= */ null);
         mController =
                 new BackAnimationController(
@@ -582,7 +583,7 @@
     @Test
     public void testBackToActivity() throws RemoteException {
         verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_ACTIVITY,
-                mCrossActivityBackAnimation.getRunner());
+                mDefaultCrossActivityBackAnimation.getRunner());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
new file mode 100644
index 0000000..8bf0111
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt
@@ -0,0 +1,264 @@
+/*
+ * 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.f
+ */
+package com.android.wm.shell.back
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.AppCompatTaskInfo
+import android.app.WindowConfiguration
+import android.graphics.Color
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.RemoteException
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.Choreographer
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.view.animation.Animation
+import android.window.BackEvent
+import android.window.BackMotionEvent
+import android.window.BackNavigationInfo
+import androidx.test.filters.SmallTest
+import com.android.internal.policy.TransitionAnimation
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.ShellTestCase
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import junit.framework.TestCase.assertEquals
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class CustomCrossActivityBackAnimationTest : ShellTestCase() {
+    @Mock private lateinit var backAnimationBackground: BackAnimationBackground
+    @Mock private lateinit var mockCloseAnimation: Animation
+    @Mock private lateinit var mockOpenAnimation: Animation
+    @Mock private lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+    @Mock private lateinit var transitionAnimation: TransitionAnimation
+    @Mock private lateinit var appCompatTaskInfo: AppCompatTaskInfo
+    @Mock private lateinit var transaction: Transaction
+
+    private lateinit var customCrossActivityBackAnimation: CustomCrossActivityBackAnimation
+    private lateinit var customAnimationLoader: CustomAnimationLoader
+
+    @Before
+    @Throws(Exception::class)
+    fun setUp() {
+        customAnimationLoader = CustomAnimationLoader(transitionAnimation)
+        customCrossActivityBackAnimation =
+            CustomCrossActivityBackAnimation(
+                context,
+                backAnimationBackground,
+                rootTaskDisplayAreaOrganizer,
+                transaction,
+                mock(Choreographer::class.java),
+                customAnimationLoader
+            )
+
+        whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(OPEN_RES_ID)))
+            .thenReturn(mockOpenAnimation)
+        whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(CLOSE_RES_ID)))
+            .thenReturn(mockCloseAnimation)
+        whenever(transaction.setColor(any(), any())).thenReturn(transaction)
+        whenever(transaction.setAlpha(any(), anyFloat())).thenReturn(transaction)
+        whenever(transaction.setCrop(any(), any())).thenReturn(transaction)
+        whenever(transaction.setRelativeLayer(any(), any(), anyInt())).thenReturn(transaction)
+        spy(customCrossActivityBackAnimation)
+    }
+
+    @Test
+    @Throws(InterruptedException::class)
+    fun receiveFinishAfterInvoke() {
+        val finishCalled = startCustomAnimation()
+        try {
+            customCrossActivityBackAnimation.getRunner().callback.onBackInvoked()
+        } catch (r: RemoteException) {
+            Assert.fail("onBackInvoked throw remote exception")
+        }
+        finishCalled.await(1, TimeUnit.SECONDS)
+    }
+
+    @Test
+    @Throws(InterruptedException::class)
+    fun receiveFinishAfterCancel() {
+        val finishCalled = startCustomAnimation()
+        try {
+            customCrossActivityBackAnimation.getRunner().callback.onBackCancelled()
+        } catch (r: RemoteException) {
+            Assert.fail("onBackCancelled throw remote exception")
+        }
+        finishCalled.await(1, TimeUnit.SECONDS)
+    }
+
+    @Test
+    @Throws(InterruptedException::class)
+    fun receiveFinishWithoutAnimationAfterInvoke() {
+        val finishCalled = startCustomAnimation(targets = arrayOf())
+        try {
+            customCrossActivityBackAnimation.getRunner().callback.onBackInvoked()
+        } catch (r: RemoteException) {
+            Assert.fail("onBackInvoked throw remote exception")
+        }
+        finishCalled.await(1, TimeUnit.SECONDS)
+    }
+
+    @Test
+    fun testLoadCustomAnimation() {
+        testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 0)
+    }
+
+    @Test
+    fun testLoadCustomAnimationNoEnter() {
+        testLoadCustomAnimation(0, CLOSE_RES_ID, 0)
+    }
+
+    @Test
+    fun testLoadWindowAnimations() {
+        testLoadCustomAnimation(0, 0, 30)
+    }
+
+    @Test
+    fun testCustomAnimationHigherThanWindowAnimations() {
+        testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 30)
+    }
+
+    private fun testLoadCustomAnimation(enterResId: Int, exitResId: Int, windowAnimations: Int) {
+        val builder =
+            BackNavigationInfo.Builder()
+                .setCustomAnimation(PACKAGE_NAME, enterResId, exitResId, Color.GREEN)
+                .setWindowAnimations(PACKAGE_NAME, windowAnimations)
+        val info = builder.build().customAnimationInfo!!
+        whenever(
+                transitionAnimation.loadAnimationAttr(
+                    eq(PACKAGE_NAME),
+                    eq(windowAnimations),
+                    anyInt(),
+                    anyBoolean()
+                )
+            )
+            .thenReturn(mockCloseAnimation)
+        whenever(transitionAnimation.loadDefaultAnimationAttr(anyInt(), anyBoolean()))
+            .thenReturn(mockOpenAnimation)
+        val result = customAnimationLoader.loadAll(info)!!
+        if (exitResId != 0) {
+            if (enterResId == 0) {
+                verify(transitionAnimation, never())
+                    .loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(enterResId))
+                verify(transitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean())
+            } else {
+                assertEquals(result.enterAnimation, mockOpenAnimation)
+            }
+            assertEquals(result.backgroundColor.toLong(), Color.GREEN.toLong())
+            assertEquals(result.closeAnimation, mockCloseAnimation)
+            verify(transitionAnimation, never())
+                .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean())
+        } else if (windowAnimations != 0) {
+            verify(transitionAnimation, times(2))
+                .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean())
+            Assert.assertEquals(result.closeAnimation, mockCloseAnimation)
+        }
+    }
+
+    private fun startCustomAnimation(
+        targets: Array<RemoteAnimationTarget> =
+            arrayOf(createAnimationTarget(false), createAnimationTarget(true))
+    ): CountDownLatch {
+        val backNavigationInfo =
+            BackNavigationInfo.Builder()
+                .setCustomAnimation(PACKAGE_NAME, OPEN_RES_ID, CLOSE_RES_ID, /*backgroundColor*/ 0)
+                .build()
+        customCrossActivityBackAnimation.prepareNextAnimation(
+            backNavigationInfo.customAnimationInfo,
+            0
+        )
+        val finishCalled = CountDownLatch(1)
+        val finishCallback = Runnable { finishCalled.countDown() }
+        customCrossActivityBackAnimation
+            .getRunner()
+            .startAnimation(targets, null, null, finishCallback)
+        customCrossActivityBackAnimation.runner.callback.onBackStarted(backMotionEventFrom(0f, 0f))
+        if (targets.isNotEmpty()) {
+            verify(mockCloseAnimation)
+                .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE))
+            verify(mockOpenAnimation)
+                .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE))
+        }
+        return finishCalled
+    }
+
+    private fun backMotionEventFrom(touchX: Float, progress: Float) =
+        BackMotionEvent(
+            /* touchX = */ touchX,
+            /* touchY = */ 0f,
+            /* progress = */ progress,
+            /* velocityX = */ 0f,
+            /* velocityY = */ 0f,
+            /* triggerBack = */ false,
+            /* swipeEdge = */ BackEvent.EDGE_LEFT,
+            /* departingAnimationTarget = */ null
+        )
+
+    private fun createAnimationTarget(open: Boolean): RemoteAnimationTarget {
+        val topWindowLeash = SurfaceControl()
+        val taskInfo = RunningTaskInfo()
+        taskInfo.appCompatTaskInfo = appCompatTaskInfo
+        taskInfo.taskDescription = ActivityManager.TaskDescription()
+        return RemoteAnimationTarget(
+            1,
+            if (open) RemoteAnimationTarget.MODE_OPENING else RemoteAnimationTarget.MODE_CLOSING,
+            topWindowLeash,
+            false,
+            Rect(),
+            Rect(),
+            -1,
+            Point(0, 0),
+            Rect(0, 0, BOUND_SIZE, BOUND_SIZE),
+            Rect(),
+            WindowConfiguration(),
+            true,
+            null,
+            null,
+            taskInfo,
+            false,
+            -1
+        )
+    }
+
+    companion object {
+        private const val BOUND_SIZE = 100
+        private const val OPEN_RES_ID = 1000
+        private const val CLOSE_RES_ID = 1001
+        private const val PACKAGE_NAME = "TestPackage"
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java
deleted file mode 100644
index 158d640..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-
-import static org.junit.Assert.assertEquals;
-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.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.app.WindowConfiguration;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.Choreographer;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.view.animation.Animation;
-import android.window.BackNavigationInfo;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner.class)
-public class CustomizeActivityAnimationTest extends ShellTestCase {
-    private static final int BOUND_SIZE = 100;
-    @Mock
-    private BackAnimationBackground mBackAnimationBackground;
-    @Mock
-    private Animation mMockCloseAnimation;
-    @Mock
-    private Animation mMockOpenAnimation;
-
-    private CustomizeActivityAnimation mCustomizeActivityAnimation;
-
-    @Before
-    public void setUp() throws Exception {
-        mCustomizeActivityAnimation = new CustomizeActivityAnimation(mContext,
-                mBackAnimationBackground, mock(SurfaceControl.Transaction.class),
-                mock(Choreographer.class));
-        spyOn(mCustomizeActivityAnimation);
-        spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation);
-    }
-
-    RemoteAnimationTarget createAnimationTarget(boolean open) {
-        SurfaceControl topWindowLeash = new SurfaceControl();
-        return new RemoteAnimationTarget(1,
-                open ? RemoteAnimationTarget.MODE_OPENING : RemoteAnimationTarget.MODE_CLOSING,
-                topWindowLeash, false, new Rect(), new Rect(), -1,
-                new Point(0, 0), new Rect(0, 0, BOUND_SIZE, BOUND_SIZE), new Rect(),
-                new WindowConfiguration(), true, null, null, null, false, -1);
-    }
-
-    @Test
-    public void receiveFinishAfterInvoke() throws InterruptedException {
-        spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader);
-        doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
-                .loadAnimation(any(), eq(false));
-        doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
-                .loadAnimation(any(), eq(true));
-
-        mCustomizeActivityAnimation.prepareNextAnimation(
-                new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
-        final RemoteAnimationTarget close = createAnimationTarget(false);
-        final RemoteAnimationTarget open = createAnimationTarget(true);
-        // start animation with remote animation targets
-        final CountDownLatch finishCalled = new CountDownLatch(1);
-        final Runnable finishCallback = finishCalled::countDown;
-        mCustomizeActivityAnimation
-                .getRunner()
-                .startAnimation(
-                        new RemoteAnimationTarget[] {close, open}, null, null, finishCallback);
-        verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
-                eq(BOUND_SIZE), eq(BOUND_SIZE));
-        verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
-                eq(BOUND_SIZE), eq(BOUND_SIZE));
-
-        try {
-            mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked();
-        } catch (RemoteException r) {
-            fail("onBackInvoked throw remote exception");
-        }
-        verify(mCustomizeActivityAnimation).onGestureCommitted();
-        finishCalled.await(1, TimeUnit.SECONDS);
-    }
-
-    @Test
-    public void receiveFinishAfterCancel() throws InterruptedException {
-        spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader);
-        doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
-                .loadAnimation(any(), eq(false));
-        doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader)
-                .loadAnimation(any(), eq(true));
-
-        mCustomizeActivityAnimation.prepareNextAnimation(
-                new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
-        final RemoteAnimationTarget close = createAnimationTarget(false);
-        final RemoteAnimationTarget open = createAnimationTarget(true);
-        // start animation with remote animation targets
-        final CountDownLatch finishCalled = new CountDownLatch(1);
-        final Runnable finishCallback = finishCalled::countDown;
-        mCustomizeActivityAnimation
-                .getRunner()
-                .startAnimation(
-                        new RemoteAnimationTarget[] {close, open}, null, null, finishCallback);
-        verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
-                eq(BOUND_SIZE), eq(BOUND_SIZE));
-        verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE),
-                eq(BOUND_SIZE), eq(BOUND_SIZE));
-
-        try {
-            mCustomizeActivityAnimation.getRunner().getCallback().onBackCancelled();
-        } catch (RemoteException r) {
-            fail("onBackCancelled throw remote exception");
-        }
-        finishCalled.await(1, TimeUnit.SECONDS);
-    }
-
-    @Test
-    public void receiveFinishWithoutAnimationAfterInvoke() throws InterruptedException {
-        mCustomizeActivityAnimation.prepareNextAnimation(
-                new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0);
-        // start animation without any remote animation targets
-        final CountDownLatch finishCalled = new CountDownLatch(1);
-        final Runnable finishCallback = finishCalled::countDown;
-        mCustomizeActivityAnimation
-                .getRunner()
-                .startAnimation(new RemoteAnimationTarget[] {}, null, null, finishCallback);
-
-        try {
-            mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked();
-        } catch (RemoteException r) {
-            fail("onBackInvoked throw remote exception");
-        }
-        verify(mCustomizeActivityAnimation).onGestureCommitted();
-        finishCalled.await(1, TimeUnit.SECONDS);
-    }
-
-    @Test
-    public void testLoadCustomAnimation() {
-        testLoadCustomAnimation(10, 20, 0);
-    }
-
-    @Test
-    public void testLoadCustomAnimationNoEnter() {
-        testLoadCustomAnimation(0, 10, 0);
-    }
-
-    @Test
-    public void testLoadWindowAnimations() {
-        testLoadCustomAnimation(0, 0, 30);
-    }
-
-    @Test
-    public void testCustomAnimationHigherThanWindowAnimations() {
-        testLoadCustomAnimation(10, 20, 30);
-    }
-
-    private void testLoadCustomAnimation(int enterResId, int exitResId, int windowAnimations) {
-        final String testPackage = "TestPackage";
-        BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
-                .setCustomAnimation(testPackage, enterResId, exitResId, Color.GREEN)
-                .setWindowAnimations(testPackage, windowAnimations);
-        final BackNavigationInfo.CustomAnimationInfo info = builder.build()
-                .getCustomAnimationInfo();
-
-        doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
-                        .mTransitionAnimation)
-                .loadAppTransitionAnimation(eq(testPackage), eq(enterResId));
-        doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
-                        .mTransitionAnimation)
-                .loadAppTransitionAnimation(eq(testPackage), eq(exitResId));
-        doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
-                        .mTransitionAnimation)
-                .loadAnimationAttr(eq(testPackage), eq(windowAnimations), anyInt(), anyBoolean());
-        doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader
-                        .mTransitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean());
-
-        CustomizeActivityAnimation.AnimationLoadResult result =
-                mCustomizeActivityAnimation.mCustomAnimationLoader.loadAll(info);
-
-        if (exitResId != 0) {
-            if (enterResId == 0) {
-                verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation,
-                        never()).loadAppTransitionAnimation(eq(testPackage), eq(enterResId));
-                verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation)
-                        .loadDefaultAnimationAttr(anyInt(), anyBoolean());
-            } else {
-                assertEquals(result.mEnterAnimation, mMockOpenAnimation);
-            }
-            assertEquals(result.mBackgroundColor, Color.GREEN);
-            assertEquals(result.mCloseAnimation, mMockCloseAnimation);
-            verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, never())
-                    .loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean());
-        } else if (windowAnimations != 0) {
-            verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation,
-                    times(2)).loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean());
-            assertEquals(result.mCloseAnimation, mMockCloseAnimation);
-        }
-    }
-}
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 5cf5a1d..f1ee325 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -467,10 +467,10 @@
 
     std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
     /*
-     * Using ui::ADISPLAY_ID_NONE for displayId here to avoid removing the callback
+     * Using ui::LogicalDisplayId::INVALID for displayId here to avoid removing the callback
      * if a TouchSpotController with the same display is removed.
      */
-    mContext.addAnimationCallback(ui::ADISPLAY_ID_NONE, func);
+    mContext.addAnimationCallback(ui::LogicalDisplayId::INVALID, func);
 }
 
 } // namespace android
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 70e5c24..c6430f7 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -109,7 +109,7 @@
 
     struct Locked {
         Presentation presentation;
-        ui::LogicalDisplayId pointerDisplayId = ui::ADISPLAY_ID_NONE;
+        ui::LogicalDisplayId pointerDisplayId = ui::LogicalDisplayId::INVALID;
 
         std::vector<gui::DisplayInfo> mDisplayInfos;
         std::unordered_map<ui::LogicalDisplayId, TouchSpotController> spotControllers;
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 070c90c..e147c56 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -174,7 +174,7 @@
         int32_t layer{0};
         float alpha{1.0f};
         SpriteTransformationMatrix transformationMatrix;
-        ui::LogicalDisplayId displayId{ui::ADISPLAY_ID_DEFAULT};
+        ui::LogicalDisplayId displayId{ui::LogicalDisplayId::DEFAULT};
 
         sp<SurfaceControl> surfaceControl;
         int32_t surfaceWidth{0};
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 7a13380..2dcb1f1 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -166,7 +166,7 @@
     PointerControllerTest();
     ~PointerControllerTest();
 
-    void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_DEFAULT);
+    void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT);
 
     sp<MockSprite> mPointerSprite;
     sp<MockPointerControllerPolicyInterface> mPolicy;
@@ -335,23 +335,23 @@
 
     // Update spots to sync state with sprite
     mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
-                                 ui::ADISPLAY_ID_DEFAULT);
+                                 ui::LogicalDisplayId::DEFAULT);
     testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
 
     // Marking the display to skip screenshot should update sprite as well
-    mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, true);
+    mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, true);
     EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true));
 
     // Update spots to sync state with sprite
     mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
-                                 ui::ADISPLAY_ID_DEFAULT);
+                                 ui::LogicalDisplayId::DEFAULT);
     testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
 
     // Reset flag and verify again
-    mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, false);
+    mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, false);
     EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
     mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
-                                 ui::ADISPLAY_ID_DEFAULT);
+                                 ui::LogicalDisplayId::DEFAULT);
     testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
 }
 
diff --git a/packages/PrintSpooler/res/values-night/themes.xml b/packages/PrintSpooler/res/values-night/themes.xml
index 3cc64a6..76fa7b9 100644
--- a/packages/PrintSpooler/res/values-night/themes.xml
+++ b/packages/PrintSpooler/res/values-night/themes.xml
@@ -24,6 +24,7 @@
     <style name="Theme.SelectPrinterActivity"
            parent="android:style/Theme.DeviceDefault">
         <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
+        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
     </style>
 
     <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault">
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index bd96025..22842f7 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -24,6 +24,7 @@
            parent="android:style/Theme.DeviceDefault.Light">
         <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item>
         <item name="android:windowLightStatusBar">true</item>
+        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
     </style>
 
     <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault.Light">
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index 05507e0..493818b 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -80,14 +80,15 @@
                 continue;
             }
             final URLSpan urlSpan = (URLSpan) clickable;
-            if (!urlSpan.getURL().startsWith(INTENT_URL_PREFIX)) {
+            final String url = urlSpan.getURL();
+            if (url == null || !url.startsWith(INTENT_URL_PREFIX)) {
                 continue;
             }
             final int start = spannable.getSpanStart(urlSpan);
             final int end = spannable.getSpanEnd(urlSpan);
             spannable.removeSpan(urlSpan);
             try {
-                final Intent intent = Intent.parseUri(urlSpan.getURL(), Intent.URI_INTENT_SCHEME);
+                final Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                 final ClickableSpan clickableSpan =
                         new ClickableSpan() {
                             @Override
@@ -98,7 +99,7 @@
                         };
                 spannable.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
             } catch (URISyntaxException e) {
-                Log.e(TAG, "Invalid URI " + urlSpan.getURL(), e);
+                Log.e(TAG, "Invalid URI " + url, e);
             }
         }
         title.setText(spannable);
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 89f54d9..9c0d29d 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -62,3 +62,10 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+  name: "allow_all_widgets_on_lockscreen_by_default"
+  namespace: "systemui"
+  description: "Allow all widgets on the lock screen by default."
+  bug: "328261690"
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 0dd956c..204429b 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -34,6 +34,13 @@
 }
 
 flag {
+   name: "priority_people_section"
+   namespace: "systemui"
+   description: "Add a new section for priority people (aka important conversations)."
+   bug: "340294566"
+}
+
+flag {
    name: "notification_minimalism_prototype"
    namespace: "systemui"
    description: "Prototype of notification minimalism; the new 'Intermediate' lockscreen customization proposal."
@@ -470,6 +477,17 @@
 }
 
 flag {
+    name: "fix_screenshot_action_dismiss_system_windows"
+    namespace: "systemui"
+    description: "Dismiss existing system windows when starting action from screenshot UI"
+    bug: "309933761"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+
+flag {
     name: "screenshot_private_profile_behavior_fix"
     namespace: "systemui"
     description: "Private profile support for screenshots"
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt
new file mode 100644
index 0000000..94620c4
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UFile
+import org.jetbrains.uast.UImportStatement
+
+class CollectAsStateDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableUastTypes(): List<Class<out UElement>> {
+        return listOf(UFile::class.java)
+    }
+
+    override fun createUastHandler(context: JavaContext): UElementHandler {
+        return object : UElementHandler() {
+            override fun visitFile(node: UFile) {
+                node.imports.forEach { importStatement ->
+                    visitImportStatement(context, importStatement)
+                }
+            }
+        }
+    }
+
+    private fun visitImportStatement(
+        context: JavaContext,
+        importStatement: UImportStatement,
+    ) {
+        val importText = importStatement.importReference?.asSourceString() ?: return
+        if (ILLEGAL_IMPORT == importText) {
+            context.report(
+                issue = ISSUE,
+                scope = importStatement,
+                location = context.getLocation(importStatement),
+                message = "collectAsState considered harmful",
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE =
+            Issue.create(
+                id = "OverlyEagerCollectAsState",
+                briefDescription = "collectAsState considered harmful",
+                explanation =
+                    """
+                go/sysui-compose#collect-as-state
+
+                Don't use collectAsState as it will set up a coroutine that keeps collecting from a
+                flow until its coroutine scope becomes inactive. This prevents the work from being
+                properly paused while the surrounding lifecycle becomes paused or stopped and is
+                therefore considered harmful.
+
+                Instead, use Flow.collectAsStateWithLifecycle(initial: T) or
+                StateFlow.collectAsStateWithLifecycle(). These APIs correctly pause the collection
+                coroutine while the lifecycle drops below the specified minActiveState (which
+                defaults to STARTED meaning that it will pause when the Compose-hosting window
+                becomes invisible).
+            """
+                        .trimIndent(),
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.ERROR,
+                implementation =
+                    Implementation(
+                        CollectAsStateDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE,
+                    ),
+            )
+
+        private val ILLEGAL_IMPORT = "androidx.compose.runtime.collectAsState"
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index cecbc47..73ac6cc 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -32,6 +32,7 @@
                 BindServiceOnMainThreadDetector.ISSUE,
                 BroadcastSentViaContextDetector.ISSUE,
                 CleanArchitectureDependencyViolationDetector.ISSUE,
+                CollectAsStateDetector.ISSUE,
                 DumpableNotRegisteredDetector.ISSUE,
                 FlowDetector.SHARED_FLOW_CREATION,
                 SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt
new file mode 100644
index 0000000..6962b4e
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class CollectAsStateDetectorTest : SystemUILintDetectorTest() {
+
+    override fun getDetector(): Detector {
+        return CollectAsStateDetector()
+    }
+
+    override fun getIssues(): List<Issue> {
+        return listOf(
+            CollectAsStateDetector.ISSUE,
+        )
+    }
+
+    @Test
+    fun testViolation() {
+        lint()
+            .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE, BAD_FILE)
+            .issues(CollectAsStateDetector.ISSUE)
+            .run()
+            .expect(
+                """
+src/com/android/internal/systemui/lint/Bad.kt:3: Error: collectAsState considered harmful [OverlyEagerCollectAsState]
+import androidx.compose.runtime.collectAsState
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+                """
+                    .trimIndent()
+            )
+    }
+
+    @Test
+    fun testNoViolation() {
+        lint()
+            .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE)
+            .issues(CollectAsStateDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    companion object {
+        private val COLLECT_AS_STATE_STUB =
+            TestFiles.kotlin(
+                """
+                package androidx.compose.runtime
+
+                fun collectAsState() {}
+            """
+                    .trimIndent()
+            )
+        private val COLLECT_WITH_LIFECYCLE_AS_STATE_STUB =
+            TestFiles.kotlin(
+                """
+                package androidx.lifecycle.compose
+
+                fun collectAsStateWithLifecycle() {}
+            """
+                    .trimIndent()
+            )
+
+        private val BAD_FILE =
+            TestFiles.kotlin(
+                """
+                package com.android.internal.systemui.lint
+
+                import androidx.compose.runtime.collectAsState
+
+                class Bad
+            """
+                    .trimIndent()
+            )
+
+        private val GOOD_FILE =
+            TestFiles.kotlin(
+                """
+                package com.android.internal.systemui.lint
+
+                import androidx.lifecycle.compose.collectAsStateWithLifecycle
+
+                class Good
+            """
+                    .trimIndent()
+            )
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index c22b50d..fa01a4b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -56,7 +56,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -77,6 +76,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.unit.times
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformButton
 import com.android.compose.animation.Easings
 import com.android.compose.animation.scene.ElementKey
@@ -111,7 +111,7 @@
     dialogFactory: BouncerDialogFactory,
     modifier: Modifier = Modifier,
 ) {
-    val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState()
+    val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsStateWithLifecycle()
     val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported)
 
     Box(
@@ -220,7 +220,7 @@
     viewModel: BouncerViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val authMethod by viewModel.authMethodViewModel.collectAsState()
+    val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
 
     Row(
         modifier =
@@ -316,7 +316,7 @@
     val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) }
     val isHeightExpanded =
         LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded
-    val authMethod by viewModel.authMethodViewModel.collectAsState()
+    val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
 
     Row(
         modifier =
@@ -480,7 +480,7 @@
     modifier: Modifier = Modifier,
 ) {
     val foldPosture: FoldPosture by foldPosture()
-    val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsState()
+    val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsStateWithLifecycle()
     val isSplitAroundTheFold = foldPosture == FoldPosture.Tabletop && isSplitAroundTheFoldRequired
     val currentSceneKey =
         if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey
@@ -562,7 +562,7 @@
     viewModel: BouncerMessageViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val message: MessageViewModel? by viewModel.message.collectAsState()
+    val message: MessageViewModel? by viewModel.message.collectAsStateWithLifecycle()
 
     DisposableEffect(Unit) {
         viewModel.onShown()
@@ -612,7 +612,7 @@
     modifier: Modifier = Modifier,
 ) {
     val authMethodViewModel: AuthMethodBouncerViewModel? by
-        viewModel.authMethodViewModel.collectAsState()
+        viewModel.authMethodViewModel.collectAsStateWithLifecycle()
 
     when (val nonNullViewModel = authMethodViewModel) {
         is PinBouncerViewModel ->
@@ -642,7 +642,7 @@
     modifier: Modifier = Modifier,
 ) {
     val authMethodViewModel: AuthMethodBouncerViewModel? by
-        viewModel.authMethodViewModel.collectAsState()
+        viewModel.authMethodViewModel.collectAsStateWithLifecycle()
 
     when (val nonNullViewModel = authMethodViewModel) {
         is PinBouncerViewModel -> {
@@ -668,7 +668,8 @@
     viewModel: BouncerViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState()
+    val actionButton: BouncerActionButtonModel? by
+        viewModel.actionButton.collectAsStateWithLifecycle()
     val appearFadeInAnimatable = remember { Animatable(0f) }
     val appearMoveAnimatable = remember { Animatable(0f) }
     val appearAnimationInitialOffset = with(LocalDensity.current) { 80.dp.toPx() }
@@ -735,7 +736,7 @@
     bouncerViewModel: BouncerViewModel,
     dialogFactory: BouncerDialogFactory,
 ) {
-    val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsState()
+    val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsStateWithLifecycle()
     var dialog: AlertDialog? by remember { mutableStateOf(null) }
 
     dialogViewModel?.let { viewModel ->
@@ -772,8 +773,8 @@
         return
     }
 
-    val selectedUserImage by viewModel.selectedUserImage.collectAsState(null)
-    val dropdownItems by viewModel.userSwitcherDropdown.collectAsState(emptyList())
+    val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null)
+    val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList())
 
     Column(
         horizontalAlignment = Alignment.CenterHorizontally,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 2dcd0ff..203bd7a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -27,7 +27,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.ExperimentalComposeUiApi
@@ -49,6 +48,7 @@
 import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformIconButton
 import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
 import com.android.systemui.common.ui.compose.SelectedUserAwareInputConnection
@@ -62,18 +62,20 @@
     modifier: Modifier = Modifier,
 ) {
     val focusRequester = remember { FocusRequester() }
-    val isTextFieldFocusRequested by viewModel.isTextFieldFocusRequested.collectAsState()
+    val isTextFieldFocusRequested by
+        viewModel.isTextFieldFocusRequested.collectAsStateWithLifecycle()
     LaunchedEffect(isTextFieldFocusRequested) {
         if (isTextFieldFocusRequested) {
             focusRequester.requestFocus()
         }
     }
 
-    val password: String by viewModel.password.collectAsState()
-    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
-    val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
-    val isImeSwitcherButtonVisible by viewModel.isImeSwitcherButtonVisible.collectAsState()
-    val selectedUserId by viewModel.selectedUserId.collectAsState()
+    val password: String by viewModel.password.collectAsStateWithLifecycle()
+    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+    val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
+    val isImeSwitcherButtonVisible by
+        viewModel.isImeSwitcherButtonVisible.collectAsStateWithLifecycle()
+    val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle()
 
     DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index d7e9c10..9c2fd64 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -30,7 +30,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -47,6 +46,7 @@
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.res.integerResource
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Easings
 import com.android.compose.modifiers.thenIf
 import com.android.internal.R
@@ -86,14 +86,15 @@
     val lineStrokeWidth = with(density) { LINE_STROKE_WIDTH_DP.dp.toPx() }
 
     // All dots that should be rendered on the grid.
-    val dots: List<PatternDotViewModel> by viewModel.dots.collectAsState()
+    val dots: List<PatternDotViewModel> by viewModel.dots.collectAsStateWithLifecycle()
     // The most recently selected dot, if the user is currently dragging.
-    val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsState()
+    val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsStateWithLifecycle()
     // The dots selected so far, if the user is currently dragging.
-    val selectedDots: List<PatternDotViewModel> by viewModel.selectedDots.collectAsState()
-    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
-    val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsState()
-    val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+    val selectedDots: List<PatternDotViewModel> by
+        viewModel.selectedDots.collectAsStateWithLifecycle()
+    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+    val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsStateWithLifecycle()
+    val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
 
     // Map of animatables for the scale of each dot, keyed by dot.
     val dotScalingAnimatables = remember(dots) { dots.associateWith { Animatable(1f) } }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 5651a46..64ace2f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -33,7 +33,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -49,6 +48,7 @@
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Easings
 import com.android.compose.grid.VerticalGrid
 import com.android.compose.modifiers.thenIf
@@ -74,12 +74,13 @@
 ) {
     DisposableEffect(Unit) { onDispose { viewModel.onHidden() } }
 
-    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
-    val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState()
-    val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState()
-    val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
+    val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle()
+    val backspaceButtonAppearance by
+        viewModel.backspaceButtonAppearance.collectAsStateWithLifecycle()
+    val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsStateWithLifecycle()
+    val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle()
     val isDigitButtonAnimationEnabled: Boolean by
-        viewModel.isDigitButtonAnimationEnabled.collectAsState()
+        viewModel.isDigitButtonAnimationEnabled.collectAsStateWithLifecycle()
 
     val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } }
     LaunchedEffect(animateFailure) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
index 1a97912..465eade 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
@@ -42,7 +42,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
 import androidx.compose.runtime.mutableStateListOf
@@ -65,6 +64,7 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Dialog
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformOutlinedButton
 import com.android.compose.animation.Easings
 import com.android.keyguard.PinShapeAdapter
@@ -86,7 +86,7 @@
     viewModel: PinBouncerViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsState()
+    val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsStateWithLifecycle()
     val shapeAnimations = rememberShapeAnimations(viewModel.pinShapes)
 
     // The display comes in two different flavors:
@@ -119,7 +119,7 @@
     hintedPinLength: Int,
     modifier: Modifier = Modifier,
 ) {
-    val pinInput: PinInputViewModel by viewModel.pinInput.collectAsState()
+    val pinInput: PinInputViewModel by viewModel.pinInput.collectAsStateWithLifecycle()
     // [ClearAll] marker pointing at the beginning of the current pin input.
     // When a new [ClearAll] token is added to the [pinInput], the clear-all animation is played
     // and the marker is advanced manually to the most recent marker. See LaunchedEffect below.
@@ -257,9 +257,10 @@
 
 @Composable
 private fun SimArea(viewModel: PinBouncerViewModel) {
-    val isLockedEsim by viewModel.isLockedEsim.collectAsState()
-    val isSimUnlockingDialogVisible by viewModel.isSimUnlockingDialogVisible.collectAsState()
-    val errorDialogMessage by viewModel.errorDialogMessage.collectAsState()
+    val isLockedEsim by viewModel.isLockedEsim.collectAsStateWithLifecycle()
+    val isSimUnlockingDialogVisible by
+        viewModel.isSimUnlockingDialogVisible.collectAsStateWithLifecycle()
+    val errorDialogMessage by viewModel.errorDialogMessage.collectAsStateWithLifecycle()
     var unlockDialog: Dialog? by remember { mutableStateOf(null) }
     var errorDialog: Dialog? by remember { mutableStateOf(null) }
     val context = LocalView.current.context
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
index c8e1450..694326d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt
@@ -35,7 +35,7 @@
  * ```
  * @Composable
  * fun YourFunction(viewModel: YourViewModel) {
- *     val selectedUserId by viewModel.selectedUserId.collectAsState()
+ *     val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle()
  *
  *     SelectedUserAwareInputConnection(selectedUserId) {
  *         TextField(...)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
index 8144d15..296fc27 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt
@@ -22,12 +22,12 @@
 import androidx.compose.foundation.layout.systemBars
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import kotlinx.coroutines.flow.StateFlow
 
 /** The bounds and [CutoutLocation] of the current display. */
@@ -45,7 +45,7 @@
     screenCornerRadius: Float,
     content: @Composable () -> Unit,
 ) {
-    val cutout by displayCutout.collectAsState()
+    val cutout by displayCutout.collectAsStateWithLifecycle()
     val screenCornerRadiusDp = with(LocalDensity.current) { screenCornerRadius.toDp() }
 
     val density = LocalDensity.current
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 08e452c..8ee8ea4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -6,13 +6,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.dimensionResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.ElementMatcher
@@ -85,8 +85,9 @@
     content: CommunalContent,
 ) {
     val coroutineScope = rememberCoroutineScope()
-    val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank)
-    val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false)
+    val currentSceneKey: SceneKey by
+        viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank)
+    val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle(initialValue = false)
     val state: MutableSceneTransitionLayoutState = remember {
         MutableSceneTransitionLayoutState(
             initialScene = currentSceneKey,
@@ -149,7 +150,8 @@
     content: CommunalContent,
     modifier: Modifier = Modifier,
 ) {
-    val backgroundColor by colors.backgroundColor.collectAsState()
+    val backgroundColor by colors.backgroundColor.collectAsStateWithLifecycle()
+
     Box(
         modifier =
             Modifier.element(Communal.Elements.Scrim)
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 02621f6..2a52c60 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
@@ -78,7 +78,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -124,6 +123,7 @@
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.compose.ui.window.Popup
 import androidx.core.view.setPadding
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.window.layout.WindowMetricsCalculator
 import com.android.compose.modifiers.thenIf
 import com.android.compose.theme.LocalAndroidColorScheme
@@ -156,20 +156,21 @@
     onOpenWidgetPicker: (() -> Unit)? = null,
     onEditDone: (() -> Unit)? = null,
 ) {
-    val communalContent by viewModel.communalContent.collectAsState(initial = emptyList())
-    val currentPopup by viewModel.currentPopup.collectAsState(initial = null)
+    val communalContent by
+        viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList())
+    val currentPopup by viewModel.currentPopup.collectAsStateWithLifecycle(initialValue = null)
     var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
     var toolbarSize: IntSize? by remember { mutableStateOf(null) }
     var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
     var isDraggingToRemove by remember { mutableStateOf(false) }
     val gridState = rememberLazyGridState()
     val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
-    val reorderingWidgets by viewModel.reorderingWidgets.collectAsState()
-    val selectedKey = viewModel.selectedKey.collectAsState()
+    val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
+    val selectedKey = viewModel.selectedKey.collectAsStateWithLifecycle()
     val removeButtonEnabled by remember {
         derivedStateOf { selectedKey.value != null || reorderingWidgets }
     }
-    val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false)
+    val isEmptyState by viewModel.isEmptyState.collectAsStateWithLifecycle(initialValue = false)
 
     val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
     val contentOffset = beforeContentPadding(contentPadding).toOffset()
@@ -303,9 +304,9 @@
 
         if (viewModel is CommunalViewModel && dialogFactory != null) {
             val isEnableWidgetDialogShowing by
-                viewModel.isEnableWidgetDialogShowing.collectAsState(false)
+                viewModel.isEnableWidgetDialogShowing.collectAsStateWithLifecycle(false)
             val isEnableWorkProfileDialogShowing by
-                viewModel.isEnableWorkProfileDialogShowing.collectAsState(false)
+                viewModel.isEnableWorkProfileDialogShowing.collectAsStateWithLifecycle(false)
 
             EnableWidgetDialog(
                 isEnableWidgetDialogVisible = isEnableWidgetDialogShowing,
@@ -860,7 +861,7 @@
     contentListState: ContentListState,
 ) {
     val context = LocalContext.current
-    val isFocusable by viewModel.isFocusable.collectAsState(initial = false)
+    val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false)
     val accessibilityLabel =
         remember(model, context) {
             model.providerInfo.loadLabel(context.packageManager).toString().trim()
@@ -868,7 +869,7 @@
     val clickActionLabel = stringResource(R.string.accessibility_action_label_select_widget)
     val removeWidgetActionLabel = stringResource(R.string.accessibility_action_label_remove_widget)
     val placeWidgetActionLabel = stringResource(R.string.accessibility_action_label_place_widget)
-    val selectedKey by viewModel.selectedKey.collectAsState()
+    val selectedKey by viewModel.selectedKey.collectAsStateWithLifecycle()
     val selectedIndex =
         selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } }
     Box(
@@ -1109,7 +1110,7 @@
 @Composable
 fun AccessibilityContainer(viewModel: BaseCommunalViewModel, content: @Composable () -> Unit) {
     val context = LocalContext.current
-    val isFocusable by viewModel.isFocusable.collectAsState(initial = false)
+    val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false)
     Box(
         modifier =
             Modifier.fillMaxWidth().wrapContentHeight().thenIf(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
index e77ade9..17dac7e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt
@@ -18,11 +18,11 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.produceState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.window.layout.WindowInfoTracker
 import com.android.systemui.fold.ui.helper.FoldPosture
 import com.android.systemui.fold.ui.helper.foldPostureInternal
@@ -32,7 +32,8 @@
 fun foldPosture(): State<FoldPosture> {
     val context = LocalContext.current
     val infoTracker = remember(context) { WindowInfoTracker.getOrCreate(context) }
-    val layoutInfo by infoTracker.windowLayoutInfo(context).collectAsState(initial = null)
+    val layoutInfo by
+        infoTracker.windowLayoutInfo(context).collectAsStateWithLifecycle(initialValue = null)
 
     return produceState<FoldPosture>(
         initialValue = FoldPosture.Folded,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
index a8d801a..67840c7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
@@ -29,7 +29,6 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
 import androidx.compose.ui.Alignment
@@ -37,6 +36,7 @@
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.theme.PlatformTheme
 import com.android.systemui.keyboard.stickykeys.shared.model.Locked
 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey
@@ -57,7 +57,7 @@
 
 @Composable
 fun StickyKeysIndicator(viewModel: StickyKeysIndicatorViewModel) {
-    val stickyKeys by viewModel.indicatorContent.collectAsState(emptyMap())
+    val stickyKeys by viewModel.indicatorContent.collectAsStateWithLifecycle(emptyMap())
     StickyKeysIndicator(stickyKeys)
 }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 4bef9ef..6d8c47d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -18,11 +18,11 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
@@ -51,7 +51,7 @@
         modifier: Modifier = Modifier,
     ) {
         val coroutineScope = rememberCoroutineScope()
-        val blueprintId by viewModel.blueprintId(coroutineScope).collectAsState()
+        val blueprintId by viewModel.blueprintId(coroutineScope).collectAsStateWithLifecycle()
         val view = LocalView.current
         DisposableEffect(view) {
             clockInteractor.clockEventController.registerListeners(view)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
index 472484a..4555f13 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt
@@ -26,13 +26,13 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
 
 /** Container for lockscreen content that handles long-press to bring up the settings menu. */
@@ -42,7 +42,8 @@
     modifier: Modifier = Modifier,
     content: @Composable BoxScope.(onSettingsMenuPlaces: (coordinates: Rect?) -> Unit) -> Unit,
 ) {
-    val isEnabled: Boolean by viewModel.isLongPressHandlingEnabled.collectAsState(initial = false)
+    val isEnabled: Boolean by
+        viewModel.isLongPressHandlingEnabled.collectAsStateWithLifecycle(initialValue = false)
     val (settingsMenuBounds, setSettingsMenuBounds) = remember { mutableStateOf<Rect?>(null) }
     val interactionSource = remember { MutableInteractionSource() }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
index 8129e41..ba25719 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
@@ -21,11 +21,11 @@
 import androidx.compose.foundation.layout.systemBars
 import androidx.compose.foundation.layout.union
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalDensity
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.plugins.clocks.ClockController
@@ -37,7 +37,7 @@
 fun rememberBurnIn(
     clockInteractor: KeyguardClockInteractor,
 ): BurnInState {
-    val clock by clockInteractor.currentClock.collectAsState()
+    val clock by clockInteractor.currentClock.collectAsStateWithLifecycle()
 
     val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) }
     val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 3152535..abff93d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -22,13 +22,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.unit.IntRect
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
@@ -67,8 +67,8 @@
     override fun SceneScope.Content(modifier: Modifier) {
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val shouldUseSplitNotificationShade by
-            viewModel.shouldUseSplitNotificationShade.collectAsState()
-        val unfoldTranslations by viewModel.unfoldTranslations.collectAsState()
+            viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+        val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
 
         LockscreenLongPress(
             viewModel = viewModel.longPress,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index 9d31955..c83f62c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -22,13 +22,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.unit.IntRect
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
@@ -70,8 +70,8 @@
     override fun SceneScope.Content(modifier: Modifier) {
         val isUdfpsVisible = viewModel.isUdfpsVisible
         val shouldUseSplitNotificationShade by
-            viewModel.shouldUseSplitNotificationShade.collectAsState()
-        val unfoldTranslations by viewModel.unfoldTranslations.collectAsState()
+            viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
+        val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
 
         LockscreenLongPress(
             viewModel = viewModel.longPress,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
index abbf0ea..aaf49ff 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard.ui.composable.modifier
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -25,6 +24,7 @@
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.boundsInWindow
 import androidx.compose.ui.layout.onPlaced
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel
@@ -44,8 +44,10 @@
     val translationYState = remember { mutableStateOf(0F) }
     val copiedParams = params.copy(translationY = { translationYState.value })
     val burnIn = viewModel.movement(copiedParams)
-    val translationX by burnIn.map { it.translationX.toFloat() }.collectAsState(initial = 0f)
-    val translationY by burnIn.map { it.translationY.toFloat() }.collectAsState(initial = 0f)
+    val translationX by
+        burnIn.map { it.translationX.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f)
+    val translationY by
+        burnIn.map { it.translationY.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f)
     translationYState.value = translationY
     val scaleViewModel by
         burnIn
@@ -55,7 +57,7 @@
                     scaleClockOnly = it.scaleClockOnly,
                 )
             }
-            .collectAsState(initial = BurnInScaleViewModel())
+            .collectAsStateWithLifecycle(initialValue = BurnInScaleViewModel())
 
     return this.graphicsLayer {
         this.translationX = if (isClock) 0F else translationX
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index 09ec76d..218779d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -25,13 +25,13 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.core.view.contains
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
 import com.android.systemui.customization.R
@@ -59,9 +59,11 @@
         onTopChanged: (top: Float?) -> Unit,
         modifier: Modifier = Modifier,
     ) {
-        val currentClock by viewModel.currentClock.collectAsState()
+        val currentClock by viewModel.currentClock.collectAsStateWithLifecycle()
         val smallTopMargin by
-            viewModel.smallClockTopMargin.collectAsState(viewModel.getSmallClockTopMargin())
+            viewModel.smallClockTopMargin.collectAsStateWithLifecycle(
+                viewModel.getSmallClockTopMargin()
+            )
         if (currentClock?.smallClock?.view == null) {
             return
         }
@@ -89,7 +91,7 @@
 
     @Composable
     fun SceneScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) {
-        val currentClock by viewModel.currentClock.collectAsState()
+        val currentClock by viewModel.currentClock.collectAsStateWithLifecycle()
         if (currentClock?.largeClock?.view == null) {
             return
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
index c37d626..3ca2b9c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/MediaCarouselSection.kt
@@ -18,9 +18,9 @@
 
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel
 import com.android.systemui.media.controls.ui.composable.MediaCarousel
@@ -40,7 +40,7 @@
 
     @Composable
     fun SceneScope.KeyguardMediaCarousel() {
-        val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsState()
+        val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle()
 
         MediaCarousel(
             isVisible = isMediaVisible,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index f48fa88..7f80dfa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -20,13 +20,13 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.thenIf
 import com.android.systemui.Flags
@@ -40,16 +40,19 @@
 import com.android.systemui.res.R
 import com.android.systemui.shade.LargeScreenHeaderHelper
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
+import dagger.Lazy
 import javax.inject.Inject
 
 @SysUISingleton
 class NotificationSection
 @Inject
 constructor(
+    private val stackScrollView: Lazy<NotificationScrollView>,
     private val viewModel: NotificationsPlaceholderViewModel,
     private val aodBurnInViewModel: AodBurnInViewModel,
     sharedNotificationContainer: SharedNotificationContainer,
@@ -88,9 +91,9 @@
     @Composable
     fun SceneScope.Notifications(burnInParams: BurnInParameters?, modifier: Modifier = Modifier) {
         val shouldUseSplitNotificationShade by
-            lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsState()
+            lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle()
         val areNotificationsVisible by
-            lockscreenContentViewModel.areNotificationsVisible.collectAsState()
+            lockscreenContentViewModel.areNotificationsVisible.collectAsStateWithLifecycle()
         val splitShadeTopMargin: Dp =
             if (Flags.centralizedStatusBarHeightFix()) {
                 LargeScreenHeaderHelper.getLargeScreenHeaderHeight(LocalContext.current).dp
@@ -103,6 +106,7 @@
         }
 
         ConstrainedNotificationStack(
+            stackScrollView = stackScrollView.get(),
             viewModel = viewModel,
             modifier =
                 modifier
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
index fc8b3b9..44bda95 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt
@@ -26,7 +26,6 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -34,6 +33,7 @@
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
@@ -160,7 +160,7 @@
     private fun Weather(
         modifier: Modifier = Modifier,
     ) {
-        val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsState()
+        val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsStateWithLifecycle()
         if (!isVisible) {
             return
         }
@@ -187,7 +187,7 @@
     private fun Date(
         modifier: Modifier = Modifier,
     ) {
-        val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsState()
+        val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsStateWithLifecycle()
         if (!isVisible) {
             return
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 63c70c9..88b8298 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -25,7 +25,6 @@
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
@@ -33,6 +32,7 @@
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntOffset
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.SceneTransitionLayout
 import com.android.compose.modifiers.thenIf
@@ -62,9 +62,9 @@
     fun DefaultClockLayout(
         modifier: Modifier = Modifier,
     ) {
-        val currentClockLayout by clockViewModel.currentClockLayout.collectAsState()
+        val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle()
         val hasCustomPositionUpdatedAnimation by
-            clockViewModel.hasCustomPositionUpdatedAnimation.collectAsState()
+            clockViewModel.hasCustomPositionUpdatedAnimation.collectAsStateWithLifecycle()
         val currentScene =
             when (currentClockLayout) {
                 KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK ->
@@ -133,7 +133,7 @@
     @Composable
     private fun SceneScope.LargeClockWithSmartSpace(shouldOffSetClockToOneHalf: Boolean = false) {
         val burnIn = rememberBurnIn(clockInteractor)
-        val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
+        val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
 
         LaunchedEffect(isLargeClockVisible) {
             if (isLargeClockVisible) {
@@ -170,8 +170,8 @@
     @Composable
     private fun SceneScope.WeatherLargeClockWithSmartSpace(modifier: Modifier = Modifier) {
         val burnIn = rememberBurnIn(clockInteractor)
-        val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState()
-        val currentClockState = clockViewModel.currentClock.collectAsState()
+        val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
+        val currentClockState = clockViewModel.currentClock.collectAsStateWithLifecycle()
 
         LaunchedEffect(isLargeClockVisible) {
             if (isLargeClockVisible) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 01d62a3..cf2e895 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -38,7 +38,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.remember
@@ -64,6 +63,7 @@
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.lerp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.NestedScrollBehavior
 import com.android.compose.animation.scene.SceneScope
@@ -112,7 +112,7 @@
     modifier: Modifier = Modifier,
     isPeekFromBottom: Boolean = false,
 ) {
-    val headsUpHeight = viewModel.headsUpHeight.collectAsState()
+    val headsUpHeight = viewModel.headsUpHeight.collectAsStateWithLifecycle()
 
     Element(
         Notifications.Elements.HeadsUpNotificationPlaceholder,
@@ -138,6 +138,7 @@
 /** Adds the space where notification stack should appear in the scene. */
 @Composable
 fun SceneScope.ConstrainedNotificationStack(
+    stackScrollView: NotificationScrollView,
     viewModel: NotificationsPlaceholderViewModel,
     modifier: Modifier = Modifier,
 ) {
@@ -146,6 +147,7 @@
             modifier.onSizeChanged { viewModel.onConstrainedAvailableSpaceChanged(it.height) }
     ) {
         NotificationPlaceholder(
+            stackScrollView = stackScrollView,
             viewModel = viewModel,
             modifier = Modifier.fillMaxSize(),
         )
@@ -178,9 +180,10 @@
         shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) {
             ScrollState(initial = 0)
         }
-    val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f)
-    val isCurrentGestureOverscroll = viewModel.isCurrentGestureOverscroll.collectAsState(false)
-    val expansionFraction by viewModel.expandFraction.collectAsState(0f)
+    val syntheticScroll = viewModel.syntheticScroll.collectAsStateWithLifecycle(0f)
+    val isCurrentGestureOverscroll =
+        viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false)
+    val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f)
 
     val navBarHeight =
         with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() }
@@ -193,7 +196,8 @@
      */
     val stackHeight = remember { mutableIntStateOf(0) }
 
-    val scrimRounding = viewModel.shadeScrimRounding.collectAsState(ShadeScrimRounding())
+    val scrimRounding =
+        viewModel.shadeScrimRounding.collectAsStateWithLifecycle(ShadeScrimRounding())
 
     // the offset for the notifications scrim. Its upper bound is 0, and its lower bound is
     // calculated in minScrimOffset. The scrim is the same height as the screen minus the
@@ -334,6 +338,7 @@
                     .debugBackground(viewModel, DEBUG_BOX_COLOR)
         ) {
             NotificationPlaceholder(
+                stackScrollView = stackScrollView,
                 viewModel = viewModel,
                 modifier =
                     Modifier.verticalNestedScrollToScene(
@@ -390,6 +395,7 @@
 
 @Composable
 private fun SceneScope.NotificationPlaceholder(
+    stackScrollView: NotificationScrollView,
     viewModel: NotificationsPlaceholderViewModel,
     modifier: Modifier = Modifier,
 ) {
@@ -408,10 +414,8 @@
                             " bounds=${coordinates.boundsInWindow()}"
                     }
                     // NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not
-                    viewModel.onStackBoundsChanged(
-                        top = positionInWindow.y,
-                        bottom = positionInWindow.y + coordinates.size.height,
-                    )
+                    stackScrollView.setStackTop(positionInWindow.y)
+                    stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height)
                 }
     ) {
         content {}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index 73cb72c..b808044 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -36,7 +36,6 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
 import androidx.compose.ui.Alignment
@@ -46,6 +45,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
@@ -64,8 +64,8 @@
     viewModel: PeopleViewModel,
     onResult: (PeopleViewModel.Result) -> Unit,
 ) {
-    val priorityTiles by viewModel.priorityTiles.collectAsState()
-    val recentTiles by viewModel.recentTiles.collectAsState()
+    val priorityTiles by viewModel.priorityTiles.collectAsStateWithLifecycle()
+    val recentTiles by viewModel.recentTiles.collectAsStateWithLifecycle()
 
     // Call [onResult] this activity when the ViewModel tells us so.
     LaunchedEffect(viewModel.result) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 2f241ce..e8da4bd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -44,7 +44,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -69,6 +68,7 @@
 import androidx.compose.ui.unit.sp
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.compose.animation.Expandable
 import com.android.compose.animation.scene.SceneScope
@@ -132,8 +132,8 @@
     val context = LocalContext.current
 
     // Collect alphas as soon as we are composed, even when not visible.
-    val alpha by viewModel.alpha.collectAsState()
-    val backgroundAlpha = viewModel.backgroundAlpha.collectAsState()
+    val alpha by viewModel.alpha.collectAsStateWithLifecycle()
+    val backgroundAlpha = viewModel.backgroundAlpha.collectAsStateWithLifecycle()
 
     var security by remember { mutableStateOf<FooterActionsSecurityButtonViewModel?>(null) }
     var foregroundServices by remember {
@@ -181,7 +181,6 @@
     val horizontalPadding = dimensionResource(R.dimen.qs_content_horizontal_padding)
     Row(
         modifier
-            .sysuiResTag("qs_footer_actions")
             .fillMaxWidth()
             .graphicsLayer { this.alpha = alpha }
             .then(backgroundModifier)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
index ca6b343..73a624a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt
@@ -21,13 +21,13 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.offset
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.modifiers.height
 import com.android.compose.modifiers.width
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
@@ -40,13 +40,13 @@
     qsSceneAdapter: QSSceneAdapter,
     modifier: Modifier = Modifier,
 ) {
-    val isShowing by viewModel.isShowing.collectAsState()
+    val isShowing by viewModel.isShowing.collectAsStateWithLifecycle()
     val mirrorAlpha by
         animateFloatAsState(
             targetValue = if (isShowing) 1f else 0f,
             label = "alphaAnimationBrightnessMirrorShowing",
         )
-    val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsState()
+    val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsStateWithLifecycle()
     val offset = IntOffset(0, mirrorOffsetAndSize.yOffset)
 
     Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = mirrorAlpha }) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 46be6b8..d109988 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -22,18 +22,19 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.MovableElementScenePicker
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
 import com.android.compose.animation.scene.ValueKey
 import com.android.compose.modifiers.thenIf
+import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding
@@ -143,7 +144,9 @@
     MovableElement(
         key = QuickSettings.Elements.Content,
         modifier =
-            modifier.fillMaxWidth().layout { measurable, constraints ->
+            modifier.sysuiResTag("quick_settings_panel").fillMaxWidth().layout {
+                measurable,
+                constraints ->
                 val placeable = measurable.measure(constraints)
                 // Use the height of the correct view based on the scene it is being composed in
                 val height = heightProvider().coerceAtLeast(0)
@@ -161,9 +164,11 @@
     state: QSSceneAdapter.State,
     modifier: Modifier = Modifier,
 ) {
-    val qsView by qsSceneAdapter.qsView.collectAsState(null)
+    val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null)
     val isCustomizing by
-        qsSceneAdapter.isCustomizerShowing.collectAsState(qsSceneAdapter.isCustomizerShowing.value)
+        qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle(
+            qsSceneAdapter.isCustomizerShowing.value
+        )
     QuickSettingsTheme {
         val context = LocalContext.current
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 6ae0efa..d76b19f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -51,7 +51,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -63,6 +62,7 @@
 import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
 import com.android.compose.animation.scene.animateSceneFloatAsState
@@ -163,7 +163,8 @@
 ) {
     val cutoutLocation = LocalDisplayCutout.current.location
 
-    val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
+    val brightnessMirrorShowing by
+        viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle()
     val contentAlpha by
         animateFloatAsState(
             targetValue = if (brightnessMirrorShowing) 0f else 1f,
@@ -198,10 +199,11 @@
                     Modifier.displayCutoutPadding()
                 },
     ) {
-        val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
-        val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
+        val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
+        val isCustomizerShowing by
+            viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
         val customizingAnimationDuration by
-            viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
+            viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
         val screenHeight = LocalRawScreenHeight.current
 
         BackHandler(
@@ -343,10 +345,10 @@
                         viewModel.qsSceneAdapter,
                         { viewModel.qsSceneAdapter.qsHeight },
                         isSplitShade = false,
-                        modifier = Modifier.sysuiResTag("quick_settings_panel")
+                        modifier = Modifier
                     )
 
-                    val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+                    val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
 
                     MediaCarousel(
                         isVisible = isMediaVisible,
@@ -362,7 +364,8 @@
                 isCustomizing = isCustomizing,
                 customizingAnimationDuration = customizingAnimationDuration,
                 lifecycleOwner = lifecycleOwner,
-                modifier = Modifier.align(Alignment.CenterHorizontally),
+                modifier =
+                    Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"),
             )
         }
         NotificationScrollingStack(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 7af9b7b..92b2b4e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -23,7 +23,6 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
@@ -34,6 +33,7 @@
 import androidx.compose.ui.input.pointer.PointerEventPass
 import androidx.compose.ui.input.pointer.motionEventSpy
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.SceneTransitionLayout
@@ -68,8 +68,9 @@
     modifier: Modifier = Modifier,
 ) {
     val coroutineScope = rememberCoroutineScope()
-    val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState()
-    val currentDestinations by viewModel.currentDestinationScenes(coroutineScope).collectAsState()
+    val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle()
+    val currentDestinations by
+        viewModel.currentDestinationScenes(coroutineScope).collectAsStateWithLifecycle()
     val state: MutableSceneTransitionLayoutState = remember {
         MutableSceneTransitionLayoutState(
             initialScene = currentSceneKey,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index d528736..00ef11d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -30,13 +30,13 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
 import com.android.compose.animation.scene.SceneScope
@@ -51,7 +51,7 @@
     modifier: Modifier = Modifier,
     content: @Composable () -> Unit,
 ) {
-    val backgroundScene by viewModel.backgroundScene.collectAsState()
+    val backgroundScene by viewModel.backgroundScene.collectAsStateWithLifecycle()
 
     Box(modifier) {
         if (backgroundScene == Scenes.Lockscreen) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index 709a416..ac3e015 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -35,7 +35,6 @@
 import androidx.compose.material3.ColorScheme
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
@@ -52,6 +51,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.max
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
 import com.android.compose.animation.scene.SceneScope
@@ -118,7 +118,7 @@
     statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
-    val isDisabled by viewModel.isDisabled.collectAsState()
+    val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
     if (isDisabled) {
         return
     }
@@ -138,7 +138,7 @@
             }
         }
 
-    val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState()
+    val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
 
     // This layout assumes it is globally positioned at (0, 0) and is the
     // same size as the screen.
@@ -271,7 +271,7 @@
     statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
-    val isDisabled by viewModel.isDisabled.collectAsState()
+    val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle()
     if (isDisabled) {
         return
     }
@@ -280,7 +280,7 @@
         derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) }
     }
 
-    val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState()
+    val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
 
     Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) {
         if (isPrivacyChipVisible) {
@@ -435,7 +435,7 @@
     modifier: Modifier = Modifier,
 ) {
     Row(modifier = modifier) {
-        val subIds by viewModel.mobileSubIds.collectAsState()
+        val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle()
 
         for (subId in subIds) {
             Spacer(modifier = Modifier.width(5.dp))
@@ -472,10 +472,12 @@
     val micSlot = stringResource(id = com.android.internal.R.string.status_bar_microphone)
     val locationSlot = stringResource(id = com.android.internal.R.string.status_bar_location)
 
-    val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
-    val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsState()
-    val isMicCameraIndicationEnabled by viewModel.isMicCameraIndicationEnabled.collectAsState()
-    val isLocationIndicationEnabled by viewModel.isLocationIndicationEnabled.collectAsState()
+    val isSingleCarrier by viewModel.isSingleCarrier.collectAsStateWithLifecycle()
+    val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsStateWithLifecycle()
+    val isMicCameraIndicationEnabled by
+        viewModel.isMicCameraIndicationEnabled.collectAsStateWithLifecycle()
+    val isLocationIndicationEnabled by
+        viewModel.isLocationIndicationEnabled.collectAsStateWithLifecycle()
 
     AndroidView(
         factory = { context ->
@@ -544,7 +546,7 @@
     viewModel: ShadeHeaderViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val privacyList by viewModel.privacyItems.collectAsState()
+    val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle()
 
     AndroidView(
         factory = { context ->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 42e6fcc..a0278a6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -45,7 +45,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -58,6 +57,7 @@
 import androidx.compose.ui.platform.LocalLifecycleOwner
 import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
 import com.android.compose.animation.scene.SceneScope
@@ -71,6 +71,7 @@
 import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
 import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
 import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
+import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.media.controls.ui.composable.MediaCarousel
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController
@@ -177,7 +178,7 @@
     modifier: Modifier = Modifier,
     shadeSession: SaveableSession,
 ) {
-    val shadeMode by viewModel.shadeMode.collectAsState()
+    val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle()
     when (shadeMode) {
         is ShadeMode.Single ->
             SingleShade(
@@ -228,8 +229,8 @@
             key = QuickSettings.SharedValues.TilesSquishiness,
             canOverflow = false
         )
-    val isClickable by viewModel.isClickable.collectAsState()
-    val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+    val isClickable by viewModel.isClickable.collectAsStateWithLifecycle()
+    val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
 
     val shouldPunchHoleBehindScrim =
         layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) ||
@@ -335,10 +336,11 @@
 ) {
     val screenCornerRadius = LocalScreenCornerRadius.current
 
-    val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
-    val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState()
+    val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
+    val isCustomizerShowing by
+        viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
     val customizingAnimationDuration by
-        viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState()
+        viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
     val lifecycleOwner = LocalLifecycleOwner.current
     val footerActionsViewModel =
         remember(lifecycleOwner, viewModel) { viewModel.getFooterActionsViewModel(lifecycleOwner) }
@@ -353,13 +355,13 @@
             .unfoldTranslationX(
                 isOnStartSide = true,
             )
-            .collectAsState(0f)
+            .collectAsStateWithLifecycle(0f)
     val unfoldTranslationXForEndSide by
         viewModel
             .unfoldTranslationX(
                 isOnStartSide = false,
             )
-            .collectAsState(0f)
+            .collectAsStateWithLifecycle(0f)
 
     val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
     val bottomPadding by
@@ -383,7 +385,8 @@
         }
     }
 
-    val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
+    val brightnessMirrorShowing by
+        viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle()
     val contentAlpha by
         animateFloatAsState(
             targetValue = if (brightnessMirrorShowing) 0f else 1f,
@@ -393,7 +396,7 @@
     viewModel.notifications.setAlphaForBrightnessMirror(contentAlpha)
     DisposableEffect(Unit) { onDispose { viewModel.notifications.setAlphaForBrightnessMirror(1f) } }
 
-    val isMediaVisible by viewModel.isMediaVisible.collectAsState()
+    val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
 
     val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha }
 
@@ -444,6 +447,7 @@
                         Column(
                             modifier =
                                 Modifier.fillMaxSize()
+                                    .sysuiResTag("expanded_qs_scroll_view")
                                     .weight(1f)
                                     .thenIf(!isCustomizerShowing) {
                                         Modifier.verticalNestedScrollToScene()
@@ -482,6 +486,7 @@
                             lifecycleOwner = lifecycleOwner,
                             modifier =
                                 Modifier.align(Alignment.CenterHorizontally)
+                                    .sysuiResTag("qs_footer_actions")
                                     .then(brightnessMirrorShowingModifier),
                         )
                     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
index 5e107c6..931ff56 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
@@ -3,9 +3,9 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.Layout
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.shadeHeaderText
 import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 
@@ -14,8 +14,8 @@
     viewModel: ShadeHeaderViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val longerText = viewModel.longerDateText.collectAsState()
-    val shorterText = viewModel.shorterDateText.collectAsState()
+    val longerText = viewModel.longerDateText.collectAsStateWithLifecycle()
+    val shorterText = viewModel.shorterDateText.collectAsStateWithLifecycle()
 
     Layout(
         contents =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
index 44b221c..3976c61 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt
@@ -19,31 +19,34 @@
 import android.view.Gravity
 import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonColors
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.LiveRegionMode
 import androidx.compose.ui.semantics.clearAndSetSemantics
 import androidx.compose.ui.semantics.contentDescription
-import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.liveRegion
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel
 import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup
@@ -60,19 +63,12 @@
 
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
-        val slice by viewModel.buttonSlice.collectAsState()
+        val slice by viewModel.buttonSlice.collectAsStateWithLifecycle()
         val label = stringResource(R.string.volume_panel_noise_control_title)
         val screenWidth: Float =
             with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() }
         var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) }
         val isClickable = viewModel.isClickable(slice)
-        val onClick =
-            if (isClickable) {
-                { with(ancPopup) { show(null, gravity) } }
-            } else {
-                null
-            }
-
         Column(
             modifier =
                 modifier.onGloballyPositioned {
@@ -81,20 +77,33 @@
             verticalArrangement = Arrangement.spacedBy(12.dp),
             horizontalAlignment = Alignment.CenterHorizontally,
         ) {
-            SliceAndroidView(
-                modifier =
-                    Modifier.height(64.dp)
-                        .fillMaxWidth()
-                        .semantics {
-                            role = Role.Button
+            Box(
+                modifier = Modifier.height(64.dp),
+            ) {
+                SliceAndroidView(
+                    modifier = modifier.fillMaxSize(),
+                    slice = slice,
+                    onWidthChanged = viewModel::onButtonSliceWidthChanged,
+                    enableAccessibility = false,
+                )
+                Button(
+                    modifier =
+                        modifier.fillMaxSize().padding(8.dp).semantics {
+                            liveRegion = LiveRegionMode.Polite
                             contentDescription = label
-                        }
-                        .clip(RoundedCornerShape(28.dp)),
-                slice = slice,
-                isEnabled = onClick != null,
-                onWidthChanged = viewModel::onButtonSliceWidthChanged,
-                onClick = onClick,
-            )
+                        },
+                    enabled = isClickable,
+                    onClick = { with(ancPopup) { show(null, gravity) } },
+                    colors =
+                        ButtonColors(
+                            contentColor = Color.Transparent,
+                            containerColor = Color.Transparent,
+                            disabledContentColor = Color.Transparent,
+                            disabledContainerColor = Color.Transparent,
+                        )
+                ) {}
+            }
+
             Text(
                 modifier = Modifier.clearAndSetSemantics {}.basicMarquee(),
                 text = label,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
index d53dbf9..15df1be 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt
@@ -23,11 +23,11 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.slice.Slice
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.animation.Expandable
@@ -67,14 +67,14 @@
 
     @Composable
     private fun Content(dialog: SystemUIDialog) {
-        val isAvailable by viewModel.isAvailable.collectAsState(true)
+        val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle(true)
 
         if (!isAvailable) {
             SideEffect { dialog.dismiss() }
             return
         }
 
-        val slice by viewModel.popupSlice.collectAsState()
+        val slice by viewModel.popupSlice.collectAsStateWithLifecycle()
         SliceAndroidView(
             modifier = Modifier.fillMaxWidth(),
             slice = slice,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
index fc5d212..23d50c5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt
@@ -16,11 +16,12 @@
 
 package com.android.systemui.volume.panel.component.anc.ui.composable
 
-import android.annotation.SuppressLint
 import android.content.Context
+import android.os.Bundle
 import android.view.ContextThemeWrapper
-import android.view.MotionEvent
 import android.view.View
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.viewinterop.AndroidView
@@ -32,14 +33,13 @@
 fun SliceAndroidView(
     slice: Slice?,
     modifier: Modifier = Modifier,
-    isEnabled: Boolean = true,
     onWidthChanged: ((Int) -> Unit)? = null,
-    onClick: (() -> Unit)? = null,
+    enableAccessibility: Boolean = true,
 ) {
     AndroidView(
         modifier = modifier,
         factory = { context: Context ->
-            ClickableSliceView(
+            ComposeSliceView(
                     ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel),
                 )
                 .apply {
@@ -47,17 +47,18 @@
                     isScrollable = false
                     importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                     setShowTitleItems(true)
-                    if (onWidthChanged != null) {
-                        addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged))
-                    }
                 }
         },
-        update = { sliceView: ClickableSliceView ->
+        update = { sliceView: ComposeSliceView ->
             sliceView.slice = slice
-            sliceView.onClick = onClick
-            sliceView.isEnabled = isEnabled
-            sliceView.isClickable = isEnabled
-        }
+            sliceView.layoutListener = onWidthChanged?.let(::OnWidthChangedLayoutListener)
+            sliceView.enableAccessibility = enableAccessibility
+        },
+        onRelease = { sliceView: ComposeSliceView ->
+            sliceView.layoutListener = null
+            sliceView.slice = null
+            sliceView.enableAccessibility = true
+        },
     )
 }
 
@@ -83,26 +84,39 @@
     }
 }
 
-/**
- * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice
- * first.
- */
-@SuppressLint("ViewConstructor") // only used in this class
-private class ClickableSliceView(context: Context) : SliceView(context) {
+private class ComposeSliceView(context: Context) : SliceView(context) {
 
-    var onClick: (() -> Unit)? = null
+    var enableAccessibility: Boolean = true
+    var layoutListener: OnLayoutChangeListener? = null
+        set(value) {
+            field?.let { removeOnLayoutChangeListener(it) }
+            field = value
+            field?.let { addOnLayoutChangeListener(it) }
+        }
 
-    init {
-        if (onClick != null) {
-            setOnClickListener {}
+    override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo?) {
+        if (enableAccessibility) {
+            super.onInitializeAccessibilityNodeInfo(info)
         }
     }
 
-    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
-        return (isSliceViewClickable && onClick != null) || super.onInterceptTouchEvent(ev)
+    override fun onInitializeAccessibilityEvent(event: AccessibilityEvent?) {
+        if (enableAccessibility) {
+            super.onInitializeAccessibilityEvent(event)
+        }
     }
 
-    override fun onClick(v: View?) {
-        onClick?.takeIf { isSliceViewClickable }?.let { it() } ?: super.onClick(v)
+    override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean {
+        return if (enableAccessibility) {
+            super.performAccessibilityAction(action, arguments)
+        } else {
+            false
+        }
+    }
+
+    override fun addChildrenForAccessibility(outChildren: ArrayList<View>?) {
+        if (enableAccessibility) {
+            super.addChildrenForAccessibility(outChildren)
+        }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
index f11c3a5..e1ae80f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
@@ -28,7 +28,6 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.remember
@@ -44,6 +43,7 @@
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Expandable
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
@@ -61,7 +61,7 @@
 
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
-        val viewModelByState by viewModelFlow.collectAsState()
+        val viewModelByState by viewModelFlow.collectAsStateWithLifecycle()
         val viewModel = viewModelByState ?: return
         val label = viewModel.label.toString()
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 12debbc..1b821d3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -29,7 +29,6 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -42,6 +41,7 @@
 import androidx.compose.ui.semantics.toggleableState
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.common.ui.compose.Icon
 import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel
 import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
@@ -56,7 +56,7 @@
 
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
-        val viewModelByState by viewModelFlow.collectAsState()
+        val viewModelByState by viewModelFlow.collectAsStateWithLifecycle()
         val viewModel = viewModelByState ?: return
         val label = viewModel.label.toString()
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
index ded63a1..237bbfd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
@@ -45,7 +45,6 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -55,6 +54,7 @@
 import androidx.compose.ui.semantics.onClick
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
 import com.android.systemui.common.ui.compose.toColor
@@ -77,9 +77,9 @@
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
         val connectedDeviceViewModel: ConnectedDeviceViewModel? by
-            viewModel.connectedDeviceViewModel.collectAsState()
+            viewModel.connectedDeviceViewModel.collectAsStateWithLifecycle()
         val deviceIconViewModel: DeviceIconViewModel? by
-            viewModel.deviceIconViewModel.collectAsState()
+            viewModel.deviceIconViewModel.collectAsStateWithLifecycle()
         val clickLabel = stringResource(R.string.volume_panel_enter_media_output_settings)
 
         Expandable(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
index d41acd9..9891b5b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt
@@ -23,11 +23,11 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.style.TextAlign
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
@@ -72,14 +72,14 @@
 
     @Composable
     private fun Content(dialog: SystemUIDialog) {
-        val isAvailable by viewModel.isAvailable.collectAsState()
+        val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle()
 
         if (!isAvailable) {
             SideEffect { dialog.dismiss() }
             return
         }
 
-        val enabledModelStates by viewModel.spatialAudioButtons.collectAsState()
+        val enabledModelStates by viewModel.spatialAudioButtons.collectAsStateWithLifecycle()
         if (enabledModelStates.isEmpty()) {
             return
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index 1def7fe..072e91a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -40,7 +40,6 @@
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -52,6 +51,7 @@
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformSliderColors
 import com.android.compose.modifiers.padding
 import com.android.systemui.res.R
@@ -84,7 +84,7 @@
             modifier = Modifier.fillMaxWidth(),
         ) {
             val sliderViewModel: SliderViewModel = viewModels.first()
-            val sliderState by viewModels.first().slider.collectAsState()
+            val sliderState by viewModels.first().slider.collectAsStateWithLifecycle()
             val sliderPadding by topSliderPadding(isExpandable)
 
             VolumeSlider(
@@ -119,7 +119,7 @@
                 Column {
                     for (index in 1..viewModels.lastIndex) {
                         val sliderViewModel: SliderViewModel = viewModels[index]
-                        val sliderState by sliderViewModel.slider.collectAsState()
+                        val sliderState by sliderViewModel.slider.collectAsStateWithLifecycle()
                         transition.AnimatedVisibility(
                             modifier = Modifier.padding(top = 16.dp),
                             visible = { it || !isExpandable },
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
index bb17499..d15430f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
@@ -18,9 +18,9 @@
 
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformSliderColors
 import com.android.compose.grid.VerticalGrid
 import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
@@ -39,7 +39,7 @@
         horizontalSpacing = 24.dp,
     ) {
         for (sliderViewModel in viewModels) {
-            val sliderState = sliderViewModel.slider.collectAsState().value
+            val sliderState = sliderViewModel.slider.collectAsStateWithLifecycle().value
             VolumeSlider(
                 modifier = Modifier.fillMaxWidth(),
                 state = sliderState,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
index 79056b2..770c5d5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
@@ -18,9 +18,9 @@
 
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformSliderDefaults
 import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
 import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel
@@ -38,7 +38,8 @@
 
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
-        val sliderViewModels: List<SliderViewModel> by viewModel.sliderViewModels.collectAsState()
+        val sliderViewModels: List<SliderViewModel> by
+            viewModel.sliderViewModels.collectAsStateWithLifecycle()
         if (sliderViewModels.isEmpty()) {
             return
         }
@@ -52,7 +53,7 @@
             val expandableViewModel: SlidersExpandableViewModel by
                 viewModel
                     .isExpandable(isPortrait)
-                    .collectAsState(SlidersExpandableViewModel.Unavailable)
+                    .collectAsStateWithLifecycle(SlidersExpandableViewModel.Unavailable)
             if (expandableViewModel is SlidersExpandableViewModel.Unavailable) {
                 return
             }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index a602e25..83b8158 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -24,7 +24,6 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -32,6 +31,7 @@
 import androidx.compose.ui.semantics.paneTitle
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
@@ -54,8 +54,8 @@
     }
 
     val accessibilityTitle = stringResource(R.string.accessibility_volume_settings)
-    val state: VolumePanelState by viewModel.volumePanelState.collectAsState()
-    val components by viewModel.componentsLayout.collectAsState(null)
+    val state: VolumePanelState by viewModel.volumePanelState.collectAsStateWithLifecycle()
+    val components by viewModel.componentsLayout.collectAsStateWithLifecycle(null)
 
     with(VolumePanelComposeScope(state)) {
         components?.let { componentsState ->
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 47a00f4..624f18d 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -133,7 +133,7 @@
         @ColorInt seed: Int,
         darkTheme: Boolean,
         style: Style
-    ) : this(seed, darkTheme, style, 0.5)
+    ) : this(seed, darkTheme, style, 0.0)
 
     @JvmOverloads
     constructor(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index ce7b60e..325a324 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -29,6 +29,7 @@
 import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.settingslib.flags.Flags.FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.broadcastDispatcher
@@ -202,6 +203,18 @@
                 .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
+    @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT)
+    @Test
+    fun hubShowsAllWidgetsByDefaultWhenFlagEnabled() =
+        testScope.runTest {
+            val setting by collectLastValue(underTest.getWidgetCategories(PRIMARY_USER))
+            assertThat(setting?.categories)
+                .isEqualTo(
+                    AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD +
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+                )
+        }
+
     private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) {
         whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id)))
             .thenReturn(disabledFlags)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index e3dd9ae..8bfa5cf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.DreamManager;
 import android.content.res.Resources;
 import android.graphics.Region;
 import android.os.Handler;
@@ -45,8 +46,10 @@
 import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
 import com.android.systemui.complication.ComplicationHostViewController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.BlurUtils;
 
 import kotlinx.coroutines.CoroutineDispatcher;
@@ -115,6 +118,12 @@
     DreamOverlayStateController mStateController;
     @Mock
     KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+    @Mock
+    ShadeInteractor mShadeInteractor;
+    @Mock
+    CommunalInteractor mCommunalInteractor;
+    @Mock
+    private DreamManager mDreamManager;
 
     DreamOverlayContainerViewController mController;
 
@@ -146,7 +155,10 @@
                 mAnimationsController,
                 mStateController,
                 mBouncerlessScrimController,
-                mKeyguardTransitionInteractor);
+                mKeyguardTransitionInteractor,
+                mShadeInteractor,
+                mCommunalInteractor,
+                mDreamManager);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
similarity index 62%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index c5d7e1f..2853264 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -23,9 +23,8 @@
 import android.app.NotificationManager.IMPORTANCE_LOW
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
-import android.platform.test.flag.junit.SetFlagsRule
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.GroupEntry
@@ -44,25 +43,29 @@
 import com.android.systemui.statusbar.notification.collection.render.NodeController
 import com.android.systemui.statusbar.notification.icon.ConversationIconManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifierImpl
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.mock
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class ConversationCoordinatorTest : SysuiTestCase() {
     // captured listeners and pluggables:
@@ -72,22 +75,20 @@
     private lateinit var peopleComparator: NotifComparator
     private lateinit var beforeRenderListListener: OnBeforeRenderListListener
 
+    private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
+    private lateinit var peopleAlertingSection: NotifSection
+
     @Mock private lateinit var pipeline: NotifPipeline
     @Mock private lateinit var conversationIconManager: ConversationIconManager
-    @Mock private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
-    @Mock private lateinit var channel: NotificationChannel
     @Mock private lateinit var headerController: NodeController
-    private lateinit var entry: NotificationEntry
-    private lateinit var entryA: NotificationEntry
-    private lateinit var entryB: NotificationEntry
 
     private lateinit var coordinator: ConversationCoordinator
 
-    @Rule @JvmField public val setFlagsRule = SetFlagsRule()
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        peopleNotificationIdentifier =
+            PeopleNotificationIdentifierImpl(mock(), GroupMembershipManagerImpl())
         coordinator =
             ConversationCoordinator(
                 peopleNotificationIdentifier,
@@ -95,7 +96,6 @@
                 HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()),
                 headerController
             )
-        whenever(channel.isImportantConversation).thenReturn(true)
 
         coordinator.attach(pipeline)
 
@@ -110,49 +110,65 @@
         if (!SortBySectionTimeFlag.isEnabled)
             peopleComparator = peopleAlertingSectioner.comparator!!
 
-        entry = NotificationEntryBuilder().setChannel(channel).build()
+        peopleAlertingSection = NotifSection(peopleAlertingSectioner, 0)
+    }
 
-        val section = NotifSection(peopleAlertingSectioner, 0)
-        entryA =
-            NotificationEntryBuilder().setChannel(channel).setSection(section).setTag("A").build()
-        entryB =
-            NotificationEntryBuilder().setChannel(channel).setSection(section).setTag("B").build()
+    @Test
+    fun priorityPeopleSectionerClaimsOnlyImportantConversations() {
+        val sectioner = coordinator.priorityPeopleSectioner
+        assertTrue(sectioner.isInSection(makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)))
+        assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_FULL_PERSON)))
+        assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_PERSON)))
+        assertFalse(sectioner.isInSection(makeEntryOfPeopleType(TYPE_NON_PERSON)))
+        assertFalse(sectioner.isInSection(NotificationEntryBuilder().build()))
     }
 
     @Test
     fun testPromotesImportantConversations() {
-        // only promote important conversations
-        assertTrue(promoter.shouldPromoteToTopLevel(entry))
+        assertTrue(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)))
+        assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_FULL_PERSON)))
+        assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_PERSON)))
+        assertFalse(promoter.shouldPromoteToTopLevel(makeEntryOfPeopleType(TYPE_NON_PERSON)))
         assertFalse(promoter.shouldPromoteToTopLevel(NotificationEntryBuilder().build()))
     }
 
     @Test
     fun testPromotedImportantConversationsMakesSummaryUnimportant() {
-        val altChildA = NotificationEntryBuilder().setTag("A").build()
-        val altChildB = NotificationEntryBuilder().setTag("B").build()
-        val summary = NotificationEntryBuilder().setId(2).setChannel(channel).build()
+        val importantChannel =
+            mock<NotificationChannel>().also {
+                whenever(it.isImportantConversation).thenReturn(true)
+            }
+        val otherChannel =
+            mock<NotificationChannel>().also {
+                whenever(it.isImportantConversation).thenReturn(false)
+            }
+        val importantChild =
+            makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) { setChannel(importantChannel) }
+        val altChildA =
+            makeEntryOfPeopleType(TYPE_FULL_PERSON) { setChannel(otherChannel).setTag("A") }
+        val altChildB =
+            makeEntryOfPeopleType(TYPE_FULL_PERSON) { setChannel(otherChannel).setTag("B") }
+        val summary =
+            makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) { setChannel(importantChannel).setId(2) }
         val groupEntry =
             GroupEntryBuilder()
                 .setParent(GroupEntry.ROOT_ENTRY)
                 .setSummary(summary)
-                .setChildren(listOf(entry, altChildA, altChildB))
+                .setChildren(listOf(importantChild, altChildA, altChildB))
                 .build()
-        assertTrue(promoter.shouldPromoteToTopLevel(entry))
+        assertTrue(promoter.shouldPromoteToTopLevel(importantChild))
         assertFalse(promoter.shouldPromoteToTopLevel(altChildA))
         assertFalse(promoter.shouldPromoteToTopLevel(altChildB))
-        NotificationEntryBuilder.setNewParent(entry, GroupEntry.ROOT_ENTRY)
-        GroupEntryBuilder.getRawChildren(groupEntry).remove(entry)
-        beforeRenderListListener.onBeforeRenderList(listOf(entry, groupEntry))
+        NotificationEntryBuilder.setNewParent(importantChild, GroupEntry.ROOT_ENTRY)
+        GroupEntryBuilder.getRawChildren(groupEntry).remove(importantChild)
+        beforeRenderListListener.onBeforeRenderList(listOf(importantChild, groupEntry))
         verify(conversationIconManager).setUnimportantConversations(eq(listOf(summary.key)))
     }
 
     @Test
     fun testInAlertingPeopleSectionWhenTheImportanceIsAtLeastDefault() {
         // GIVEN
-        val alertingEntry =
-            NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_DEFAULT).build()
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(alertingEntry))
-            .thenReturn(TYPE_PERSON)
+        val alertingEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_DEFAULT) }
 
         // put alerting people notifications in this section
         assertThat(peopleAlertingSectioner.isInSection(alertingEntry)).isTrue()
@@ -162,10 +178,7 @@
     @EnableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
     fun testInAlertingPeopleSectionWhenTheImportanceIsLowerThanDefault() {
         // GIVEN
-        val silentEntry =
-                NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(silentEntry))
-                .thenReturn(TYPE_PERSON)
+        val silentEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_LOW) }
 
         // THEN put silent people notifications in alerting section
         assertThat(peopleAlertingSectioner.isInSection(silentEntry)).isTrue()
@@ -175,10 +188,7 @@
     @DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
     fun testInSilentPeopleSectionWhenTheImportanceIsLowerThanDefault() {
         // GIVEN
-        val silentEntry =
-            NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(silentEntry))
-            .thenReturn(TYPE_PERSON)
+        val silentEntry = makeEntryOfPeopleType(TYPE_PERSON) { setImportance(IMPORTANCE_LOW) }
 
         // THEN put silent people notifications in this section
         assertThat(peopleSilentSectioner.isInSection(silentEntry)).isTrue()
@@ -191,18 +201,14 @@
     @Test
     fun testNotInPeopleSection() {
         // GIVEN
-        val entry =
-            NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_LOW).build()
+        val entry = makeEntryOfPeopleType(TYPE_NON_PERSON) { setImportance(IMPORTANCE_LOW) }
         val importantEntry =
-            NotificationEntryBuilder().setChannel(channel).setImportance(IMPORTANCE_HIGH).build()
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(entry))
-            .thenReturn(TYPE_NON_PERSON)
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(importantEntry))
-            .thenReturn(TYPE_NON_PERSON)
+            makeEntryOfPeopleType(TYPE_NON_PERSON) { setImportance(IMPORTANCE_HIGH) }
 
         // THEN - only put people notification either silent or alerting
-        if (!SortBySectionTimeFlag.isEnabled)
+        if (!SortBySectionTimeFlag.isEnabled) {
             assertThat(peopleSilentSectioner.isInSection(entry)).isFalse()
+        }
         assertThat(peopleAlertingSectioner.isInSection(importantEntry)).isFalse()
     }
 
@@ -210,22 +216,16 @@
     fun testInAlertingPeopleSectionWhenThereIsAnImportantChild() {
         // GIVEN
         val altChildA =
-            NotificationEntryBuilder().setTag("A").setImportance(IMPORTANCE_DEFAULT).build()
-        val altChildB = NotificationEntryBuilder().setTag("B").setImportance(IMPORTANCE_LOW).build()
-        val summary =
-            NotificationEntryBuilder()
-                .setId(2)
-                .setImportance(IMPORTANCE_LOW)
-                .setChannel(channel)
-                .build()
+            makeEntryOfPeopleType(TYPE_NON_PERSON) { setTag("A").setImportance(IMPORTANCE_DEFAULT) }
+        val altChildB =
+            makeEntryOfPeopleType(TYPE_NON_PERSON) { setTag("B").setImportance(IMPORTANCE_LOW) }
+        val summary = makeEntryOfPeopleType(TYPE_PERSON) { setId(2).setImportance(IMPORTANCE_LOW) }
         val groupEntry =
             GroupEntryBuilder()
                 .setParent(GroupEntry.ROOT_ENTRY)
                 .setSummary(summary)
                 .setChildren(listOf(altChildA, altChildB))
                 .build()
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(summary))
-            .thenReturn(TYPE_PERSON)
         // THEN
         assertThat(peopleAlertingSectioner.isInSection(groupEntry)).isTrue()
     }
@@ -233,10 +233,12 @@
     @Test
     @DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
     fun testComparatorPutsImportantPeopleFirst() {
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
-            .thenReturn(TYPE_IMPORTANT_PERSON)
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
-            .thenReturn(TYPE_PERSON)
+        val entryA =
+            makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON) {
+                setSection(peopleAlertingSection).setTag("A")
+            }
+        val entryB =
+            makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("B") }
 
         // only put people notifications in this section
         assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(-1)
@@ -245,10 +247,10 @@
     @Test
     @DisableFlags(Flags.FLAG_SORT_SECTION_BY_TIME)
     fun testComparatorEquatesPeopleWithSameType() {
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
-            .thenReturn(TYPE_PERSON)
-        whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryB))
-            .thenReturn(TYPE_PERSON)
+        val entryA =
+            makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("A") }
+        val entryB =
+            makeEntryOfPeopleType(TYPE_PERSON) { setSection(peopleAlertingSection).setTag("B") }
 
         // only put people notifications in this section
         assertThat(peopleComparator.compare(entryA, entryB)).isEqualTo(0)
@@ -259,4 +261,23 @@
     fun testNoSecondarySortForConversations() {
         assertThat(peopleAlertingSectioner.comparator).isNull()
     }
+
+    private fun makeEntryOfPeopleType(
+        @PeopleNotificationType type: Int,
+        buildBlock: NotificationEntryBuilder.() -> Unit = {}
+    ): NotificationEntry {
+        val channel: NotificationChannel = mock()
+        whenever(channel.isImportantConversation).thenReturn(type == TYPE_IMPORTANT_PERSON)
+        val entry =
+            NotificationEntryBuilder()
+                .updateRanking {
+                    it.setIsConversation(type != TYPE_NON_PERSON)
+                    it.setShortcutInfo(if (type >= TYPE_FULL_PERSON) mock() else null)
+                    it.setChannel(channel)
+                }
+                .also(buildBlock)
+                .build()
+        assertEquals(type, peopleNotificationIdentifier.getPeopleNotificationType(entry))
+        return entry
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index 50ae985..ce134e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -31,9 +31,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.compose.animation.scene.ObservableTransitionState;
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
@@ -75,7 +76,7 @@
 import org.mockito.verification.VerificationMode;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class VisualStabilityCoordinatorTest extends SysuiTestCase {
 
@@ -86,6 +87,7 @@
     @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener;
+    @Mock private SeenNotificationsInteractor mSeenNotificationsInteractor;
     @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private VisibilityLocationProvider mVisibilityLocationProvider;
     @Mock private VisualStabilityProvider mVisualStabilityProvider;
@@ -121,6 +123,7 @@
                 mHeadsUpManager,
                 mShadeAnimationInteractor,
                 mJavaAdapter,
+                mSeenNotificationsInteractor,
                 mStatusBarStateController,
                 mVisibilityLocationProvider,
                 mVisualStabilityProvider,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
index 1f0812d..ee9fd349 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt
@@ -44,13 +44,4 @@
                 collectLastValue(kosmos.notificationStackAppearanceInteractor.shadeScrimBounds)
             assertThat(stackBounds).isEqualTo(bounds)
         }
-
-    @Test
-    fun onStackBoundsChanged() =
-        kosmos.testScope.runTest {
-            underTest.onStackBoundsChanged(top = 5f, bottom = 500f)
-            assertThat(kosmos.notificationStackAppearanceInteractor.stackTop.value).isEqualTo(5f)
-            assertThat(kosmos.notificationStackAppearanceInteractor.stackBottom.value)
-                .isEqualTo(500f)
-        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index f2ce745..da17366 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -660,9 +660,6 @@
 
             overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
-            keyguardInteractor.setNotificationContainerBounds(
-                NotificationContainerBounds(top = 1f, bottom = 2f)
-            )
 
             assertThat(maxNotifications).isEqualTo(10)
 
@@ -691,9 +688,6 @@
 
             overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
-            keyguardInteractor.setNotificationContainerBounds(
-                NotificationContainerBounds(top = 1f, bottom = 2f)
-            )
 
             assertThat(maxNotifications).isEqualTo(10)
 
@@ -728,9 +722,6 @@
 
             overrideResource(R.bool.config_use_split_notification_shade, false)
             configurationRepository.onAnyConfigurationChange()
-            keyguardInteractor.setNotificationContainerBounds(
-                NotificationContainerBounds(top = 1f, bottom = 2f)
-            )
 
             // -1 means No Limit
             assertThat(maxNotifications).isEqualTo(-1)
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
index f644584f..5755dcd 100644
--- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
@@ -47,6 +47,7 @@
         android:layout_gravity="center"
         android:contentDescription="@null"
         android:scaleType="fitXY"
+        android:importantForAccessibility="no"
         app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
         app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
         app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
index 46b8e46..05f6fae 100644
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
@@ -229,6 +229,7 @@
         android:layout_gravity="center"
         android:contentDescription="@null"
         android:scaleType="fitXY"
+        android:importantForAccessibility="no"
         app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
         app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
         app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
index d51fe58..fa4d9a8 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
@@ -222,6 +222,7 @@
         android:layout_gravity="center"
         android:contentDescription="@null"
         android:scaleType="fitXY"
+        android:importantForAccessibility="no"
         app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
         app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
         app:layout_constraintStart_toStartOf="@+id/biometric_icon"
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index c1be37a..a51d8ff 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -23,7 +23,6 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.remember
@@ -32,6 +31,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.PlatformSlider
 import com.android.systemui.brightness.shared.GammaBrightness
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
@@ -107,10 +107,13 @@
     viewModel: BrightnessSliderViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val gamma: Int by viewModel.currentBrightness.map { it.value }.collectAsState(initial = 0)
+    val gamma: Int by
+        viewModel.currentBrightness.map { it.value }.collectAsStateWithLifecycle(initialValue = 0)
     val coroutineScope = rememberCoroutineScope()
     val restriction by
-        viewModel.policyRestriction.collectAsState(initial = PolicyRestriction.NoRestriction)
+        viewModel.policyRestriction.collectAsStateWithLifecycle(
+            initialValue = PolicyRestriction.NoRestriction
+        )
 
     BrightnessSlider(
         gammaValue = gamma,
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index 8efc66d..ba236ba 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -66,11 +66,11 @@
 import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance;
 import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel;
 
-import java.util.ArrayList;
-
 import kotlin.Unit;
 import kotlin.jvm.functions.Function0;
 
+import java.util.ArrayList;
+
 /**
  * Handles the visual elements and animations for the clipboard overlay.
  */
@@ -109,6 +109,7 @@
     private View mDismissButton;
     private LinearLayout mActionContainer;
     private ClipboardOverlayCallbacks mClipboardCallbacks;
+    private ActionButtonViewBinder mActionButtonViewBinder = new ActionButtonViewBinder();
 
     public ClipboardOverlayView(Context context) {
         this(context, null);
@@ -152,14 +153,15 @@
 
     private void bindDefaultActionChips() {
         if (screenshotShelfUi2()) {
-            ActionButtonViewBinder.INSTANCE.bind(mRemoteCopyChip,
+            mActionButtonViewBinder.bind(mRemoteCopyChip,
                     ActionButtonViewModel.Companion.withNextId(
                             new ActionButtonAppearance(
                                     Icon.createWithResource(mContext,
                                             R.drawable.ic_baseline_devices_24).loadDrawable(
                                             mContext),
                                     null,
-                                    mContext.getString(R.string.clipboard_send_nearby_description)),
+                                    mContext.getString(R.string.clipboard_send_nearby_description),
+                                    true),
                             new Function0<>() {
                                 @Override
                                 public Unit invoke() {
@@ -169,12 +171,14 @@
                                     return null;
                                 }
                             }));
-            ActionButtonViewBinder.INSTANCE.bind(mShareChip,
+            mActionButtonViewBinder.bind(mShareChip,
                     ActionButtonViewModel.Companion.withNextId(
                             new ActionButtonAppearance(
                                     Icon.createWithResource(mContext,
                                             R.drawable.ic_screenshot_share).loadDrawable(mContext),
-                                    null, mContext.getString(com.android.internal.R.string.share)),
+                                    null,
+                                    mContext.getString(com.android.internal.R.string.share),
+                                    true),
                             new Function0<>() {
                                 @Override
                                 public Unit invoke() {
@@ -512,9 +516,9 @@
     private View constructShelfActionChip(RemoteAction action, Runnable onFinish) {
         View chip = LayoutInflater.from(mContext).inflate(
                 R.layout.shelf_action_chip, mActionContainer, false);
-        ActionButtonViewBinder.INSTANCE.bind(chip, ActionButtonViewModel.Companion.withNextId(
+        mActionButtonViewBinder.bind(chip, ActionButtonViewModel.Companion.withNextId(
                 new ActionButtonAppearance(action.getIcon().loadDrawable(mContext),
-                        action.getTitle(), action.getTitle()), new Function0<>() {
+                        action.getTitle(), action.getTitle(), false), new Function0<>() {
                     @Override
                     public Unit invoke() {
                         try {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index f437032..971ab11 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.communal
 
 import android.provider.Settings
-import android.service.dreams.Flags.dreamTracksFocus
 import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.CoreStartable
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -143,12 +142,10 @@
                 }
         }
 
-        if (dreamTracksFocus()) {
-            bgScope.launch {
-                communalInteractor.isIdleOnCommunal.collectLatest {
-                    withContext(mainDispatcher) {
-                        notificationShadeWindowController.setGlanceableHubShowing(it)
-                    }
+        bgScope.launch {
+            communalInteractor.isIdleOnCommunal.collectLatest {
+                withContext(mainDispatcher) {
+                    notificationShadeWindowController.setGlanceableHubShowing(it)
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
index 03f54c8..5cd15f2 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt
@@ -17,15 +17,23 @@
 package com.android.systemui.communal.data.model
 
 import android.appwidget.AppWidgetProviderInfo
+import com.android.settingslib.flags.Flags.allowAllWidgetsOnLockscreenByDefault
 
 /**
  * The widget categories to display on communal hub (where categories is a bitfield with values that
  * match those in {@link AppWidgetProviderInfo}).
  */
 @JvmInline
-value class CommunalWidgetCategories(
-    // The default is keyguard widgets.
-    val categories: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
-) {
+value class CommunalWidgetCategories(val categories: Int = defaultCategories) {
     fun contains(category: Int) = (categories and category) == category
+
+    companion object {
+        val defaultCategories: Int
+            get() {
+                return AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or
+                    if (allowAllWidgetsOnLockscreenByDefault())
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+                    else 0
+            }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
index 9debe0e..88cb64c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt
@@ -18,7 +18,6 @@
 
 import android.app.admin.DevicePolicyManager
 import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
-import android.appwidget.AppWidgetProviderInfo
 import android.content.IntentFilter
 import android.content.pm.UserInfo
 import android.provider.Settings
@@ -108,10 +107,9 @@
             .onStart { emit(Unit) }
             .map {
                 CommunalWidgetCategories(
-                    // The default is to show only keyguard widgets.
                     secureSettings.getIntForUser(
                         GLANCEABLE_HUB_CONTENT_SETTING,
-                        AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+                        CommunalWidgetCategories.defaultCategories,
                         user.id
                     )
                 )
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
index f9de609..3e5126a 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt
@@ -75,7 +75,7 @@
                 scope = bgScope,
                 // Start this eagerly since the value can be accessed synchronously.
                 started = SharingStarted.Eagerly,
-                initialValue = CommunalWidgetCategories().categories
+                initialValue = CommunalWidgetCategories.defaultCategories
             )
 
     private val workProfileUserInfoCallbackFlow: Flow<UserInfo?> = conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 6e04339..60006c6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.dreams;
 
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
+
 import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
 import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion;
 import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion;
@@ -23,8 +25,10 @@
 import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows;
 
 import android.animation.Animator;
+import android.app.DreamManager;
 import android.content.res.Resources;
 import android.graphics.Region;
 import android.os.Handler;
@@ -37,7 +41,9 @@
 import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
 import com.android.systemui.complication.ComplicationHostViewController;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
 import com.android.systemui.dreams.dagger.DreamOverlayModule;
@@ -45,10 +51,12 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.util.ViewController;
 
 import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.flow.FlowKt;
 
 import java.util.Arrays;
 
@@ -68,6 +76,8 @@
     private final DreamOverlayStateController mStateController;
     private final LowLightTransitionCoordinator mLowLightTransitionCoordinator;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+    private final ShadeInteractor mShadeInteractor;
+    private final CommunalInteractor mCommunalInteractor;
 
     private final ComplicationHostViewController mComplicationHostViewController;
 
@@ -87,9 +97,10 @@
 
     // Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
     private final Handler mHandler;
-    private final CoroutineDispatcher mMainDispatcher;
+    private final CoroutineDispatcher mBackgroundDispatcher;
     private final int mDreamOverlayMaxTranslationY;
     private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
+    private final DreamManager mDreamManager;
 
     private long mJitterStartTimeMillis;
 
@@ -178,7 +189,7 @@
             LowLightTransitionCoordinator lowLightTransitionCoordinator,
             BlurUtils blurUtils,
             @Main Handler handler,
-            @Main CoroutineDispatcher mainDispatcher,
+            @Background CoroutineDispatcher backgroundDispatcher,
             @Main Resources resources,
             @Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
             @Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
@@ -188,18 +199,23 @@
             DreamOverlayAnimationsController animationsController,
             DreamOverlayStateController stateController,
             BouncerlessScrimController bouncerlessScrimController,
-            KeyguardTransitionInteractor keyguardTransitionInteractor) {
+            KeyguardTransitionInteractor keyguardTransitionInteractor,
+            ShadeInteractor shadeInteractor,
+            CommunalInteractor communalInteractor,
+            DreamManager dreamManager) {
         super(containerView);
         mDreamOverlayContentView = contentView;
         mStatusBarViewController = statusBarViewController;
         mBlurUtils = blurUtils;
         mDreamOverlayAnimationsController = animationsController;
         mStateController = stateController;
+        mCommunalInteractor = communalInteractor;
         mLowLightTransitionCoordinator = lowLightTransitionCoordinator;
 
         mBouncerlessScrimController = bouncerlessScrimController;
 
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+        mShadeInteractor = shadeInteractor;
 
         mComplicationHostViewController = complicationHostViewController;
         mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
@@ -211,11 +227,12 @@
                         ViewGroup.LayoutParams.MATCH_PARENT));
 
         mHandler = handler;
-        mMainDispatcher = mainDispatcher;
+        mBackgroundDispatcher = backgroundDispatcher;
         mMaxBurnInOffset = maxBurnInOffset;
         mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
         mMillisUntilFullJitter = millisUntilFullJitter;
         mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor;
+        mDreamManager = dreamManager;
     }
 
     @Override
@@ -238,11 +255,21 @@
         mView.getRootSurfaceControl().setTouchableRegion(emptyRegion);
         emptyRegion.recycle();
 
-        collectFlow(
-                mView,
-                mKeyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState),
-                isFinished -> mAnyBouncerShowing = isFinished,
-                mMainDispatcher);
+        if (dreamHandlesBeingObscured()) {
+            collectFlow(
+                    mView,
+                    FlowKt.distinctUntilChanged(combineFlows(
+                            mKeyguardTransitionInteractor.isFinishedInStateWhere(
+                                    KeyguardState::isBouncerState),
+                            mShadeInteractor.isAnyExpanded(),
+                            mCommunalInteractor.isCommunalShowing(),
+                            (anyBouncerShowing, shadeExpanded, communalShowing) -> {
+                                mAnyBouncerShowing = anyBouncerShowing;
+                                return anyBouncerShowing || shadeExpanded || communalShowing;
+                            })),
+                    mDreamManager::setDreamIsObscured,
+                    mBackgroundDispatcher);
+        }
 
         // Start dream entry animations. Skip animations for low light clock.
         if (!mStateController.isLowLightActive()) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 67c5564..1404340 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -29,11 +29,13 @@
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.shared.ComposeLockscreen
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
 import com.android.systemui.statusbar.notification.shared.NotificationAvalancheSuppression
 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
 import javax.inject.Inject
 
 /** A class in which engineers can define flag dependencies */
@@ -49,6 +51,7 @@
         NotificationsLiveDataStoreRefactor.token dependsOn NotificationIconContainerRefactor.token
         FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
         NotificationAvalancheSuppression.token dependsOn VisualInterruptionRefactor.token
+        PriorityPeopleSection.token dependsOn SortBySectionTimeFlag.token
 
         // SceneContainer dependencies
         SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index dbaa297..68a252b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -37,6 +37,7 @@
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
+import android.util.Log;
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
@@ -212,21 +213,27 @@
     @AnyThread
     @Override
     public Slice onBindSlice(Uri sliceUri) {
-        Trace.beginSection("KeyguardSliceProvider#onBindSlice");
-        Slice slice;
-        synchronized (this) {
-            ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
-            if (needsMediaLocked()) {
-                addMediaLocked(builder);
-            } else {
-                builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+        Slice slice = null;
+        try {
+            Trace.beginSection("KeyguardSliceProvider#onBindSlice");
+            synchronized (this) {
+                ListBuilder builder = new ListBuilder(getContext(), mSliceUri,
+                        ListBuilder.INFINITY);
+                if (needsMediaLocked()) {
+                    addMediaLocked(builder);
+                } else {
+                    builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
+                }
+                addNextAlarmLocked(builder);
+                addZenModeLocked(builder);
+                addPrimaryActionLocked(builder);
+                slice = builder.build();
             }
-            addNextAlarmLocked(builder);
-            addZenModeLocked(builder);
-            addPrimaryActionLocked(builder);
-            slice = builder.build();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Could not initialize slice", e);
+        } finally {
+            Trace.endSection();
         }
-        Trace.endSection();
         return slice;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 2d7b737..7285739 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -97,6 +97,7 @@
 
     /** Bounds of the notification container. */
     val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy {
+        SceneContainerFlag.assertInLegacyMode()
         combine(
                 _notificationPlaceholderBounds,
                 sharedNotificationContainerInteractor.get().configurationBasedDimensions,
@@ -115,6 +116,7 @@
     }
 
     fun setNotificationContainerBounds(position: NotificationContainerBounds) {
+        SceneContainerFlag.assertInLegacyMode()
         _notificationPlaceholderBounds.value = position
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 30c6718..8f9a70980 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -218,6 +218,8 @@
             .map { step -> step.to }
             .shareIn(scope, SharingStarted.Eagerly, replay = 1)
 
+    val currentTransitionInfo: StateFlow<TransitionInfo> = repository.currentTransitionInfoInternal
+
     /** The from state of the last [TransitionState.STARTED] transition. */
     // TODO: is it performant to have several SharedFlows side by side instead of one?
     @SuppressLint("SharedFlowCreation")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
index 6e00aa7..3baeb76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt
@@ -131,7 +131,7 @@
         val newTransition =
             TransitionInfo(
                 ownerName = this::class.java.simpleName,
-                from = transitionInteractor.getStartedState(),
+                from = transitionInteractor.currentTransitionInfo.value.to,
                 to = state,
                 animator = null,
                 modeOnCanceled = TransitionModeOnCanceled.REVERSE
@@ -150,7 +150,7 @@
     private suspend fun handleTransition(transition: ObservableTransitionState.Transition) {
         if (transition.fromScene == Scenes.Lockscreen) {
             if (currentTransitionId != null) {
-                val currentToState = transitionInteractor.getStartedState()
+                val currentToState = transitionInteractor.currentTransitionInfo.value.to
                 if (currentToState == UNDEFINED) {
                     transitionKtfTo(transitionInteractor.getStartedFromState())
                 }
@@ -169,6 +169,8 @@
     }
 
     private suspend fun transitionKtfTo(state: KeyguardState) {
+        // TODO(b/330311871): This is based on a sharedFlow and thus might not be up-to-date and
+        //  cause a race condition. (There is no known scenario that is currently affected.)
         val currentTransition = transitionInteractor.transitionState.value
         if (currentTransition.isFinishedIn(state)) {
             // This is already the state we want to be in
@@ -199,7 +201,7 @@
     }
 
     private suspend fun startTransitionFromLockscreen() {
-        val currentState = transitionInteractor.getStartedState()
+        val currentState = transitionInteractor.currentTransitionInfo.value.to
         val newTransition =
             TransitionInfo(
                 ownerName = this::class.java.simpleName,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 218967c..7c745bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -57,9 +57,9 @@
         addTransition(SmartspaceMoveTransition(config, clockViewModel))
     }
 
-    open class VisibilityBoundsTransition() : Transition() {
-        var captureSmartspace: Boolean = false
-
+    abstract class VisibilityBoundsTransition() : Transition() {
+        abstract val captureSmartspace: Boolean
+        protected val TAG = this::class.simpleName!!
         override fun captureEndValues(transition: TransitionValues) = captureValues(transition)
         override fun captureStartValues(transition: TransitionValues) = captureValues(transition)
         override fun getTransitionProperties(): Array<String> = TRANSITION_PROPERTIES
@@ -76,7 +76,7 @@
                 parent.findViewById<View>(sharedR.id.bc_smartspace_view)
                     ?: parent.findViewById<View>(R.id.keyguard_slice_view)
             if (targetSSView == null) {
-                Log.e(TAG, "Failed to find smartspace equivalent target for animation")
+                Log.e(TAG, "Failed to find smartspace equivalent target under $parent")
                 return
             }
             transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect()
@@ -109,14 +109,12 @@
             var fromIsVis = fromVis == View.VISIBLE
             var fromAlpha = startValues.values[PROP_ALPHA] as Float
             val fromBounds = startValues.values[PROP_BOUNDS] as Rect
-            val fromSSBounds =
-                if (captureSmartspace) startValues.values[SMARTSPACE_BOUNDS] as Rect else null
+            val fromSSBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect?
 
             val toView = endValues.view
             val toVis = endValues.values[PROP_VISIBILITY] as Int
             val toBounds = endValues.values[PROP_BOUNDS] as Rect
-            val toSSBounds =
-                if (captureSmartspace) endValues.values[SMARTSPACE_BOUNDS] as Rect else null
+            val toSSBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect?
             val toIsVis = toVis == View.VISIBLE
             val toAlpha = if (toIsVis) 1f else 0f
 
@@ -221,9 +219,6 @@
             private const val SMARTSPACE_BOUNDS = "ClockSizeTransition:SSBounds"
             private val TRANSITION_PROPERTIES =
                 arrayOf(PROP_VISIBILITY, PROP_ALPHA, PROP_BOUNDS, SMARTSPACE_BOUNDS)
-
-            private val DEBUG = false
-            private val TAG = VisibilityBoundsTransition::class.simpleName!!
         }
     }
 
@@ -232,18 +227,24 @@
         val viewModel: KeyguardClockViewModel,
         val smartspaceViewModel: KeyguardSmartspaceViewModel,
     ) : VisibilityBoundsTransition() {
+        override val captureSmartspace = !viewModel.isLargeClockVisible.value
+
         init {
             duration = CLOCK_IN_MILLIS
             startDelay = CLOCK_IN_START_DELAY_MILLIS
             interpolator = CLOCK_IN_INTERPOLATOR
-            captureSmartspace =
-                !viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled
 
             if (viewModel.isLargeClockVisible.value) {
                 viewModel.currentClock.value?.let {
+                    if (DEBUG) Log.i(TAG, "Large Clock In: ${it.largeClock.layout.views}")
                     it.largeClock.layout.views.forEach { addTarget(it) }
                 }
+                    ?: run {
+                        Log.e(TAG, "No large clock set, falling back")
+                        addTarget(R.id.lockscreen_clock_view_large)
+                    }
             } else {
+                if (DEBUG) Log.i(TAG, "Small Clock In")
                 addTarget(R.id.lockscreen_clock_view)
             }
         }
@@ -282,7 +283,6 @@
             val CLOCK_IN_INTERPOLATOR = Interpolators.LINEAR_OUT_SLOW_IN
             const val SMALL_CLOCK_IN_MOVE_SCALE =
                 CLOCK_IN_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_DOWN_MILLIS.toFloat()
-            private val TAG = ClockFaceInTransition::class.simpleName!!
         }
     }
 
@@ -291,18 +291,24 @@
         val viewModel: KeyguardClockViewModel,
         val smartspaceViewModel: KeyguardSmartspaceViewModel,
     ) : VisibilityBoundsTransition() {
+        override val captureSmartspace = viewModel.isLargeClockVisible.value
+
         init {
             duration = CLOCK_OUT_MILLIS
             interpolator = CLOCK_OUT_INTERPOLATOR
-            captureSmartspace =
-                viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled
 
             if (viewModel.isLargeClockVisible.value) {
+                if (DEBUG) Log.i(TAG, "Small Clock Out")
                 addTarget(R.id.lockscreen_clock_view)
             } else {
                 viewModel.currentClock.value?.let {
+                    if (DEBUG) Log.i(TAG, "Large Clock Out: ${it.largeClock.layout.views}")
                     it.largeClock.layout.views.forEach { addTarget(it) }
                 }
+                    ?: run {
+                        Log.e(TAG, "No large clock set, falling back")
+                        addTarget(R.id.lockscreen_clock_view_large)
+                    }
             }
         }
 
@@ -339,7 +345,6 @@
             val CLOCK_OUT_INTERPOLATOR = Interpolators.LINEAR
             const val SMALL_CLOCK_OUT_MOVE_SCALE =
                 CLOCK_OUT_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_UP_MILLIS.toFloat()
-            private val TAG = ClockFaceOutTransition::class.simpleName!!
         }
     }
 
@@ -348,6 +353,8 @@
         val config: IntraBlueprintTransition.Config,
         viewModel: KeyguardClockViewModel,
     ) : VisibilityBoundsTransition() {
+        override val captureSmartspace = false
+
         init {
             duration =
                 if (viewModel.isLargeClockVisible.value) STATUS_AREA_MOVE_UP_MILLIS
@@ -367,4 +374,8 @@
             const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L
         }
     }
+
+    companion object {
+        val DEBUG = true
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index b072534..d09e997 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -360,8 +360,10 @@
         )
         keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
         mediaCarousel.repeatWhenAttached {
-            mediaCarouselViewModel.onAttached()
-            mediaCarouselScrollHandler.scrollToStart()
+            if (mediaFlags.isMediaControlsRefactorEnabled()) {
+                mediaCarouselViewModel.onAttached()
+                mediaCarouselScrollHandler.scrollToStart()
+            }
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 listenForAnyStateToGoneKeyguardTransition(this)
                 listenForAnyStateToLockscreenTransition(this)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
index 5c17fd1..3bda775 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt
@@ -20,9 +20,9 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel
 
 @Composable
@@ -30,8 +30,8 @@
     viewModel: EditModeViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val gridLayout by viewModel.gridLayout.collectAsState()
-    val tiles by viewModel.tiles.collectAsState(emptyList())
+    val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
+    val tiles by viewModel.tiles.collectAsStateWithLifecycle(emptyList())
 
     BackHandler { viewModel.stopEditing() }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index dc43091..bac0f60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -53,7 +53,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -72,6 +71,7 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Expandable
 import com.android.compose.theme.colorAttr
 import com.android.systemui.common.shared.model.Icon
@@ -116,8 +116,8 @@
             tiles.forEach { it.startListening(token) }
             onDispose { tiles.forEach { it.stopListening(token) } }
         }
-        val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsState()
-        val columns by gridSizeInteractor.columns.collectAsState()
+        val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+        val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
 
         TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
             items(
@@ -150,7 +150,7 @@
         val state: TileUiState by
             tile.state
                 .mapLatest { it.toUiState() }
-                .collectAsState(initial = tile.currentState.toUiState())
+                .collectAsStateWithLifecycle(initialValue = tile.currentState.toUiState())
         val context = LocalContext.current
 
         Expandable(
@@ -201,10 +201,13 @@
         val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
             onAddTile(it, POSITION_AT_END)
         }
-        val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsState(initial = emptySet())
+        val iconOnlySpecs by
+            iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle(
+                initialValue = emptySet()
+            )
         val isIconOnly: (TileSpec) -> Boolean =
             remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } }
-        val columns by gridSizeInteractor.columns.collectAsState()
+        val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
 
         TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
             // These Text are just placeholders to see the different sections. Not final UI.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index 2f32d72..2dab7c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -17,15 +17,15 @@
 package com.android.systemui.qs.panels.ui.compose
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
 
 @Composable
 fun TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
-    val gridLayout by viewModel.gridLayout.collectAsState()
-    val tiles by viewModel.tileViewModels.collectAsState(emptyList())
+    val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle()
+    val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList())
 
     gridLayout.TileGrid(tiles, modifier)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 4e290e6..6694878 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -20,7 +20,6 @@
 import android.app.NotificationManager
 import android.content.Context
 import android.content.Intent
-import android.content.pm.LauncherApps
 import android.content.res.Resources
 import android.net.Uri
 import android.os.Handler
@@ -63,7 +62,6 @@
     private val panelInteractor: PanelInteractor,
     private val issueRecordingState: IssueRecordingState,
     private val iActivityManager: IActivityManager,
-    private val launcherApps: LauncherApps,
 ) :
     RecordingService(
         controller,
@@ -85,7 +83,7 @@
         when (intent?.action) {
             ACTION_START -> {
                 TraceUtils.traceStart(
-                    contentResolver,
+                    this,
                     DEFAULT_TRACE_TAGS,
                     DEFAULT_BUFFER_SIZE,
                     DEFAULT_IS_INCLUDING_WINSCOPE,
@@ -104,11 +102,7 @@
             }
             ACTION_STOP,
             ACTION_STOP_NOTIF -> {
-                // ViewCapture needs to save it's data before it is disabled, or else the data will
-                // be lost. This is expected to change in the near future, and when that happens
-                // this line should be removed.
-                launcherApps.saveViewCaptureData()
-                TraceUtils.traceStop(contentResolver)
+                TraceUtils.traceStop(this)
                 issueRecordingState.isRecording = false
             }
             ACTION_SHARE -> {
@@ -142,7 +136,7 @@
 
     private fun shareRecording(screenRecording: Uri?) {
         val traces =
-            TraceUtils.traceDump(contentResolver, TRACE_FILE_NAME).getOrElse {
+            TraceUtils.traceDump(this, TRACE_FILE_NAME).getOrElse {
                 Log.v(
                     TAG,
                     "Traces were not present. This can happen if users double" +
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 4eca51d..4ab0918 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -33,10 +33,11 @@
 import android.view.WindowManagerGlobal
 import com.android.app.tracing.coroutines.launch
 import com.android.internal.infra.ServiceConnector
-import com.android.systemui.Flags.screenshotActionDismissSystemWindows
+import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.screenshot.proxy.SystemUiProxy
 import com.android.systemui.settings.DisplayTracker
 import com.android.systemui.shared.system.ActivityManagerWrapper
 import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -54,8 +55,8 @@
     private val activityManagerWrapper: ActivityManagerWrapper,
     @Application private val applicationScope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
+    private val systemUiProxy: SystemUiProxy,
     private val displayTracker: DisplayTracker,
-    private val keyguardController: ScreenshotKeyguardController,
 ) {
     /**
      * Execute the given intent with startActivity while performing operations for screenshot action
@@ -83,14 +84,12 @@
         options: ActivityOptions?,
         transitionCoordinator: ExitTransitionCoordinator?,
     ) {
-        if (screenshotActionDismissSystemWindows()) {
-            keyguardController.dismiss()
+        if (Flags.fixScreenshotActionDismissSystemWindows()) {
             activityManagerWrapper.closeSystemWindows(
                 CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT
             )
-        } else {
-            dismissKeyguard()
         }
+        systemUiProxy.dismissKeyguard()
         transitionCoordinator?.startExit()
 
         if (user == myUserHandle()) {
@@ -110,27 +109,6 @@
         }
     }
 
-    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
-        ServiceConnector.Impl(
-            context,
-            Intent(context, ScreenshotProxyService::class.java),
-            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
-            context.userId,
-            IScreenshotProxy.Stub::asInterface,
-        )
-
-    private suspend fun dismissKeyguard() {
-        val completion = CompletableDeferred<Unit>()
-        val onDoneBinder =
-            object : IOnDoneCallback.Stub() {
-                override fun onDone(success: Boolean) {
-                    completion.complete(Unit)
-                }
-            }
-        proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
-        completion.await()
-    }
-
     private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> =
         ServiceConnector.Impl<ICrossProfileService>(
             context,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
deleted file mode 100644
index 7696bbe..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.screenshot
-
-import android.content.Context
-import android.content.Intent
-import com.android.internal.infra.ServiceConnector
-import javax.inject.Inject
-import kotlinx.coroutines.CompletableDeferred
-
-open class ScreenshotKeyguardController @Inject constructor(context: Context) {
-    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
-        ServiceConnector.Impl(
-            context,
-            Intent(context, ScreenshotProxyService::class.java),
-            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
-            context.userId,
-            IScreenshotProxy.Stub::asInterface
-        )
-
-    suspend fun dismiss() {
-        val completion = CompletableDeferred<Unit>()
-        val onDoneBinder =
-            object : IOnDoneCallback.Stub() {
-                override fun onDone(success: Boolean) {
-                    completion.complete(Unit)
-                }
-            }
-        proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
-        completion.await()
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 1e66cd1..846884f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -31,6 +31,7 @@
 import android.view.WindowManager
 import android.window.OnBackInvokedCallback
 import android.window.OnBackInvokedDispatcher
+import androidx.appcompat.content.res.AppCompatResources
 import androidx.core.animation.doOnEnd
 import androidx.core.animation.doOnStart
 import com.android.internal.logging.UiEventLogger
@@ -58,6 +59,7 @@
     private val logger: UiEventLogger,
     private val viewModel: ScreenshotViewModel,
     private val windowManager: WindowManager,
+    shelfViewBinder: ScreenshotShelfViewBinder,
     private val thumbnailObserver: ThumbnailObserver,
     @Assisted private val context: Context,
     @Assisted private val displayId: Int
@@ -69,7 +71,17 @@
     override var callbacks: ScreenshotView.ScreenshotViewCallback? = null
     override var screenshot: ScreenshotData? = null
         set(value) {
-            viewModel.setScreenshotBitmap(value?.bitmap)
+            value?.let {
+                viewModel.setScreenshotBitmap(it.bitmap)
+                val badgeBg =
+                    AppCompatResources.getDrawable(context, R.drawable.overlay_badge_background)
+                val user = it.userHandle
+                if (badgeBg != null && user != null) {
+                    viewModel.setScreenshotBadge(
+                        context.packageManager.getUserBadgedIcon(badgeBg, user)
+                    )
+                }
+            }
             field = value
         }
 
@@ -81,7 +93,7 @@
     private val animationController = ScreenshotAnimationController(view)
 
     init {
-        ScreenshotShelfViewBinder.bind(
+        shelfViewBinder.bind(
             view,
             viewModel,
             LayoutInflater.from(context),
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
index 2243ade..36aa39f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt
@@ -23,8 +23,9 @@
 import com.android.systemui.res.R
 import com.android.systemui.screenshot.ui.TransitioningIconDrawable
 import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
+import javax.inject.Inject
 
-object ActionButtonViewBinder {
+class ActionButtonViewBinder @Inject constructor() {
     /** Binds the given view to the given view-model */
     fun bind(view: View, viewModel: ActionButtonViewModel) {
         val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon)
@@ -36,6 +37,10 @@
         // Note we never re-bind a view to a different ActionButtonViewModel, different view
         // models would remove/create separate views.
         drawable?.setIcon(viewModel.appearance.icon)
+        iconView.setImageDrawable(viewModel.appearance.icon)
+        if (!viewModel.appearance.tint) {
+            iconView.setImageTintList(null)
+        }
         textView.text = viewModel.appearance.label
 
         viewModel.appearance.customBackground?.also {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
index 89f904a..c7bc50cb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt
@@ -35,10 +35,13 @@
 import com.android.systemui.screenshot.ui.viewmodel.AnimationState
 import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
 import com.android.systemui.util.children
+import javax.inject.Inject
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 
-object ScreenshotShelfViewBinder {
+class ScreenshotShelfViewBinder
+@Inject
+constructor(private val buttonViewBinder: ActionButtonViewBinder) {
     fun bind(
         view: ScreenshotShelfView,
         viewModel: ScreenshotViewModel,
@@ -68,6 +71,7 @@
         dismissButton.setOnClickListener {
             onDismissalRequested(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, null)
         }
+        val badgeView = view.requireViewById<ImageView>(R.id.screenshot_badge)
 
         // use immediate dispatcher to ensure screenshot bitmap is set before animation
         view.repeatWhenAttached(Dispatchers.Main.immediate) {
@@ -87,6 +91,12 @@
                         }
                     }
                     launch {
+                        viewModel.badge.collect { badge ->
+                            badgeView.setImageDrawable(badge)
+                            badgeView.visibility = if (badge != null) View.VISIBLE else View.GONE
+                        }
+                    }
+                    launch {
                         viewModel.previewAction.collect { onClick ->
                             previewView.setOnClickListener { onClick?.invoke() }
                         }
@@ -151,14 +161,14 @@
             val currentView: View? = actionsContainer.getChildAt(index)
             if (action.id == currentView?.tag) {
                 // Same ID, update the display
-                ActionButtonViewBinder.bind(currentView, action)
+                buttonViewBinder.bind(currentView, action)
             } else {
                 // Different ID. Removals have already happened so this must
                 // mean that the new action must be inserted here.
                 val actionButton =
                     layoutInflater.inflate(R.layout.shelf_action_chip, actionsContainer, false)
                 actionsContainer.addView(actionButton, index)
-                ActionButtonViewBinder.bind(actionButton, action)
+                buttonViewBinder.bind(actionButton, action)
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
index 2982ea0..42ad326 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt
@@ -25,5 +25,6 @@
     val icon: Drawable?,
     val label: CharSequence?,
     val description: CharSequence,
+    val tint: Boolean = true,
     val customBackground: Drawable? = null,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
index 5f36f73..81bc281 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.screenshot.ui.viewmodel
 
 import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
 import android.util.Log
 import android.view.accessibility.AccessibilityManager
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -25,6 +26,8 @@
 class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) {
     private val _preview = MutableStateFlow<Bitmap?>(null)
     val preview: StateFlow<Bitmap?> = _preview
+    private val _badge = MutableStateFlow<Drawable?>(null)
+    val badge: StateFlow<Drawable?> = _badge
     private val _previewAction = MutableStateFlow<(() -> Unit)?>(null)
     val previewAction: StateFlow<(() -> Unit)?> = _previewAction
     private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>())
@@ -39,6 +42,10 @@
         _preview.value = bitmap
     }
 
+    fun setScreenshotBadge(badge: Drawable?) {
+        _badge.value = badge
+    }
+
     fun setPreviewAction(onClick: () -> Unit) {
         _previewAction.value = onClick
     }
@@ -109,6 +116,7 @@
 
     fun reset() {
         _preview.value = null
+        _badge.value = null
         _previewAction.value = null
         _actions.value = listOf()
         _animationState.value = AnimationState.NOT_STARTED
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index 3d0fd89..af2c197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -31,8 +31,10 @@
 import com.android.systemui.statusbar.notification.icon.ConversationIconManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.PeopleNotificationType
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
 import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE
 import javax.inject.Inject
 
 /**
@@ -81,6 +83,13 @@
         }
     }
 
+    val priorityPeopleSectioner =
+            object : NotifSectioner("Priority People", BUCKET_PRIORITY_PEOPLE) {
+                override fun isInSection(entry: ListEntry): Boolean {
+                    return getPeopleType(entry) == TYPE_IMPORTANT_PERSON
+                }
+            }
+
     // TODO(b/330193582): Rename to just "People"
     val peopleAlertingSectioner = object : NotifSectioner("People(alerting)", BUCKET_PEOPLE) {
         override fun isInSection(entry: ListEntry): Boolean  {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 933eb20..42bf4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -31,15 +31,20 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.expansionChanges
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
+import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.headsUpEvents
 import com.android.systemui.util.asIndenting
@@ -106,6 +111,10 @@
     }
 
     private fun attachUnseenFilter(pipeline: NotifPipeline) {
+        if (NotificationMinimalismPrototype.V2.isEnabled) {
+            pipeline.addPromoter(unseenNotifPromoter)
+            pipeline.addOnBeforeTransformGroupsListener(::pickOutTopUnseenNotif)
+        }
         pipeline.addFinalizeFilter(unseenNotifFilter)
         pipeline.addCollectionListener(collectionListener)
         scope.launch { trackUnseenFilterSettingChanges() }
@@ -263,7 +272,10 @@
     }
 
     private fun unseenFeatureEnabled(): Flow<Boolean> {
-        if (NotificationMinimalismPrototype.V1.isEnabled) {
+        if (
+            NotificationMinimalismPrototype.V1.isEnabled ||
+                NotificationMinimalismPrototype.V2.isEnabled
+        ) {
             return flowOf(true)
         }
         return secureSettings
@@ -334,6 +346,57 @@
             }
         }
 
+    private fun pickOutTopUnseenNotif(list: List<ListEntry>) {
+        if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return
+        // Only ever elevate a top unseen notification on keyguard, not even locked shade
+        if (statusBarStateController.state != StatusBarState.KEYGUARD) {
+            seenNotificationsInteractor.setTopUnseenNotification(null)
+            return
+        }
+        // On keyguard pick the top-ranked unseen or ongoing notification to elevate
+        seenNotificationsInteractor.setTopUnseenNotification(
+            list
+                .asSequence()
+                .flatMap {
+                    when (it) {
+                        is NotificationEntry -> listOfNotNull(it)
+                        is GroupEntry -> it.children
+                        else -> error("unhandled type of $it")
+                    }
+                }
+                .filter { shouldIgnoreUnseenCheck(it) || it in unseenNotifications }
+                .minByOrNull { it.ranking.rank }
+        )
+    }
+
+    @VisibleForTesting
+    internal val unseenNotifPromoter =
+        object : NotifPromoter("$TAG-unseen") {
+            override fun shouldPromoteToTopLevel(child: NotificationEntry): Boolean =
+                if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false
+                else
+                    seenNotificationsInteractor.isTopUnseenNotification(child) &&
+                        NotificationMinimalismPrototype.V2.ungroupTopUnseen
+        }
+
+    val unseenNotifSectioner =
+        object : NotifSectioner("Unseen", BUCKET_FOREGROUND_SERVICE) {
+            override fun isInSection(entry: ListEntry): Boolean {
+                if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return false
+                if (
+                    seenNotificationsInteractor.isTopUnseenNotification(entry.representativeEntry)
+                ) {
+                    return true
+                }
+                if (entry !is GroupEntry) {
+                    return false
+                }
+                return entry.children.any {
+                    seenNotificationsInteractor.isTopUnseenNotification(it)
+                }
+            }
+        }
+
     @VisibleForTesting
     internal val unseenNotifFilter =
         object : NotifFilter("$TAG-unseen") {
@@ -351,7 +414,9 @@
              * allow seen notifications to appear in the locked shade.
              */
             private fun isOnKeyguard(): Boolean =
-                if (
+                if (NotificationMinimalismPrototype.V2.isEnabled) {
+                    false // disable this feature under this prototype
+                } else if (
                     NotificationMinimalismPrototype.V1.isEnabled &&
                         NotificationMinimalismPrototype.V1.showOnLockedShade
                 ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 36c12a7..4506385 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -24,47 +24,51 @@
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
 import javax.inject.Inject
 
 /**
- * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the
- * Coordinators can register their respective callbacks.
+ * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the Coordinators can
+ * register their respective callbacks.
  */
 interface NotifCoordinators : Coordinator, PipelineDumpable
 
 @CoordinatorScope
-class NotifCoordinatorsImpl @Inject constructor(
-        sectionStyleProvider: SectionStyleProvider,
-        featureFlags: FeatureFlags,
-        dataStoreCoordinator: DataStoreCoordinator,
-        hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
-        hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
-        keyguardCoordinator: KeyguardCoordinator,
-        rankingCoordinator: RankingCoordinator,
-        colorizedFgsCoordinator: ColorizedFgsCoordinator,
-        deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
-        bubbleCoordinator: BubbleCoordinator,
-        headsUpCoordinator: HeadsUpCoordinator,
-        gutsCoordinator: GutsCoordinator,
-        conversationCoordinator: ConversationCoordinator,
-        debugModeCoordinator: DebugModeCoordinator,
-        groupCountCoordinator: GroupCountCoordinator,
-        groupWhenCoordinator: GroupWhenCoordinator,
-        mediaCoordinator: MediaCoordinator,
-        preparationCoordinator: PreparationCoordinator,
-        remoteInputCoordinator: RemoteInputCoordinator,
-        rowAlertTimeCoordinator: RowAlertTimeCoordinator,
-        rowAppearanceCoordinator: RowAppearanceCoordinator,
-        stackCoordinator: StackCoordinator,
-        shadeEventCoordinator: ShadeEventCoordinator,
-        smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
-        viewConfigCoordinator: ViewConfigCoordinator,
-        visualStabilityCoordinator: VisualStabilityCoordinator,
-        sensitiveContentCoordinator: SensitiveContentCoordinator,
-        dismissibilityCoordinator: DismissibilityCoordinator,
-        dreamCoordinator: DreamCoordinator,
-        statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
+class NotifCoordinatorsImpl
+@Inject
+constructor(
+    sectionStyleProvider: SectionStyleProvider,
+    featureFlags: FeatureFlags,
+    dataStoreCoordinator: DataStoreCoordinator,
+    hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
+    hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
+    keyguardCoordinator: KeyguardCoordinator,
+    rankingCoordinator: RankingCoordinator,
+    colorizedFgsCoordinator: ColorizedFgsCoordinator,
+    deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
+    bubbleCoordinator: BubbleCoordinator,
+    headsUpCoordinator: HeadsUpCoordinator,
+    gutsCoordinator: GutsCoordinator,
+    conversationCoordinator: ConversationCoordinator,
+    debugModeCoordinator: DebugModeCoordinator,
+    groupCountCoordinator: GroupCountCoordinator,
+    groupWhenCoordinator: GroupWhenCoordinator,
+    mediaCoordinator: MediaCoordinator,
+    preparationCoordinator: PreparationCoordinator,
+    remoteInputCoordinator: RemoteInputCoordinator,
+    rowAlertTimeCoordinator: RowAlertTimeCoordinator,
+    rowAppearanceCoordinator: RowAppearanceCoordinator,
+    stackCoordinator: StackCoordinator,
+    shadeEventCoordinator: ShadeEventCoordinator,
+    smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
+    viewConfigCoordinator: ViewConfigCoordinator,
+    visualStabilityCoordinator: VisualStabilityCoordinator,
+    sensitiveContentCoordinator: SensitiveContentCoordinator,
+    dismissibilityCoordinator: DismissibilityCoordinator,
+    dreamCoordinator: DreamCoordinator,
+    statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
 ) : NotifCoordinators {
 
     private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
@@ -114,6 +118,12 @@
         // Manually add Ordered Sections
         mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
         mOrderedSections.add(colorizedFgsCoordinator.sectioner) // ForegroundService
+        if (NotificationMinimalismPrototype.V2.isEnabled) {
+            mOrderedSections.add(keyguardCoordinator.unseenNotifSectioner) // Unseen (FGS)
+        }
+        if (PriorityPeopleSection.isEnabled) {
+            mOrderedSections.add(conversationCoordinator.priorityPeopleSectioner) // Priority People
+        }
         mOrderedSections.add(conversationCoordinator.peopleAlertingSectioner) // People Alerting
         if (!SortBySectionTimeFlag.isEnabled) {
             mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent
@@ -124,22 +134,26 @@
 
         sectionStyleProvider.setMinimizedSections(setOf(rankingCoordinator.minimizedSectioner))
         if (SortBySectionTimeFlag.isEnabled) {
-            sectionStyleProvider.setSilentSections(listOf(
+            sectionStyleProvider.setSilentSections(
+                listOf(
                     rankingCoordinator.silentSectioner,
                     rankingCoordinator.minimizedSectioner,
-            ))
+                )
+            )
         } else {
-            sectionStyleProvider.setSilentSections(listOf(
+            sectionStyleProvider.setSilentSections(
+                listOf(
                     conversationCoordinator.peopleSilentSectioner,
                     rankingCoordinator.silentSectioner,
                     rankingCoordinator.minimizedSectioner,
-            ))
+                )
+            )
         }
     }
 
     /**
-     * Sends the pipeline to each coordinator when the pipeline is ready to accept
-     * [Pluggable]s, [NotifCollectionListener]s and [NotifLifetimeExtender]s.
+     * Sends the pipeline to each coordinator when the pipeline is ready to accept [Pluggable]s,
+     * [NotifCollectionListener]s and [NotifLifetimeExtender]s.
      */
     override fun attach(pipeline: NotifPipeline) {
         for (c in mCoreCoordinators) {
@@ -155,10 +169,11 @@
      * As part of the NotifPipeline dumpable, dumps the list of coordinators; sections are omitted
      * as they are dumped in the RenderStageManager instead.
      */
-    override fun dumpPipeline(d: PipelineDumper) = with(d) {
-        dump("core coordinators", mCoreCoordinators)
-        dump("normal coordinators", mCoordinators)
-    }
+    override fun dumpPipeline(d: PipelineDumper) =
+        with(d) {
+            dump("core coordinators", mCoreCoordinators)
+            dump("normal coordinators", mCoordinators)
+        }
 
     companion object {
         private const val TAG = "NotifCoordinators"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 350e88e..caa6c17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -38,6 +38,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
+import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -63,6 +65,7 @@
     public static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
     private final DelayableExecutor mDelayableExecutor;
     private final HeadsUpManager mHeadsUpManager;
+    private final SeenNotificationsInteractor mSeenNotificationsInteractor;
     private final ShadeAnimationInteractor mShadeAnimationInteractor;
     private final StatusBarStateController mStatusBarStateController;
     private final JavaAdapter mJavaAdapter;
@@ -101,6 +104,7 @@
             HeadsUpManager headsUpManager,
             ShadeAnimationInteractor shadeAnimationInteractor,
             JavaAdapter javaAdapter,
+            SeenNotificationsInteractor seenNotificationsInteractor,
             StatusBarStateController statusBarStateController,
             VisibilityLocationProvider visibilityLocationProvider,
             VisualStabilityProvider visualStabilityProvider,
@@ -109,6 +113,7 @@
         mHeadsUpManager = headsUpManager;
         mShadeAnimationInteractor = shadeAnimationInteractor;
         mJavaAdapter = javaAdapter;
+        mSeenNotificationsInteractor = seenNotificationsInteractor;
         mVisibilityLocationProvider = visibilityLocationProvider;
         mVisualStabilityProvider = visualStabilityProvider;
         mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -142,8 +147,15 @@
     private final NotifStabilityManager mNotifStabilityManager =
             new NotifStabilityManager("VisualStabilityCoordinator") {
                 private boolean canMoveForHeadsUp(NotificationEntry entry) {
-                    return entry != null && mHeadsUpManager.isHeadsUpEntry(entry.getKey())
-                            && !mVisibilityLocationProvider.isInVisibleLocation(entry);
+                    if (entry == null) {
+                        return false;
+                    }
+                    boolean isTopUnseen = NotificationMinimalismPrototype.V2.isEnabled()
+                            && mSeenNotificationsInteractor.isTopUnseenNotification(entry);
+                    if (isTopUnseen || mHeadsUpManager.isHeadsUpEntry(entry.getKey())) {
+                        return !mVisibilityLocationProvider.isInVisibleLocation(entry);
+                    }
+                    return false;
                 }
 
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
index 5c844bc..e2c9e02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt
@@ -41,6 +41,9 @@
 
     /** Stats about the list of notifications attached to the shade */
     val notifStats = MutableStateFlow(NotifStats.empty)
+
+    /** The key of the top unseen notification */
+    val topUnseenNotificationKey = MutableStateFlow<String?>(null)
 }
 
 /** Represents the notification list, comprised of groups and individual notifications. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
index 1f7ab96..42828d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractor.kt
@@ -17,7 +17,9 @@
 package com.android.systemui.statusbar.notification.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
 import javax.inject.Inject
 import kotlinx.coroutines.flow.StateFlow
 
@@ -36,4 +38,15 @@
     fun setHasFilteredOutSeenNotifications(value: Boolean) {
         notificationListRepository.hasFilteredOutSeenNotifications.value = value
     }
+
+    /** Set the entry that is identified as the top unseen notification. */
+    fun setTopUnseenNotification(entry: NotificationEntry?) {
+        if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) return
+        notificationListRepository.topUnseenNotificationKey.value = entry?.key
+    }
+
+    /** Determine if the given notification is the top unseen notification. */
+    fun isTopUnseenNotification(entry: NotificationEntry?): Boolean =
+        if (NotificationMinimalismPrototype.V2.isUnexpectedlyInLegacyMode()) false
+        else entry != null && notificationListRepository.topUnseenNotificationKey.value == entry.key
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 89aa3ab..9e0dd8fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -21,6 +21,7 @@
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PRIORITY_PEOPLE;
 import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import android.annotation.Nullable;
@@ -130,7 +131,8 @@
             case BUCKET_HEADS_UP: return Notifications.Notification.SECTION_HEADS_UP;
             case BUCKET_FOREGROUND_SERVICE:
                 return Notifications.Notification.SECTION_FOREGROUND_SERVICE;
-            case BUCKET_PEOPLE: return Notifications.Notification.SECTION_PEOPLE;
+            case BUCKET_PEOPLE, BUCKET_PRIORITY_PEOPLE:
+                return Notifications.Notification.SECTION_PEOPLE;
             case BUCKET_ALERTING: return Notifications.Notification.SECTION_ALERTING;
             case BUCKET_SILENT: return Notifications.Notification.SECTION_SILENT;
         }
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 747cb3c..4f1056c 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
@@ -590,7 +590,9 @@
             mMenuRow.setAppName(mAppName);
         }
         if (mIsSummaryWithChildren) {
-            if (!AsyncGroupHeaderViewInflation.isEnabled()) {
+            if (AsyncGroupHeaderViewInflation.isEnabled()) {
+                mChildrenContainer.updateGroupHeaderExpandState();
+            } else {
                 // We create the header from the background thread instead
                 mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
                         isConversation());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
index 8889a10..bf37036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt
@@ -24,6 +24,11 @@
 /** Helper for reading or using the minimalism prototype flag state. */
 @Suppress("NOTHING_TO_INLINE")
 object NotificationMinimalismPrototype {
+
+    val version: Int by lazy {
+        SystemProperties.getInt("persist.notification_minimalism_prototype.version", 2)
+    }
+
     object V1 {
         /** The aconfig flag name */
         const val FLAG_NAME = Flags.FLAG_NOTIFICATION_MINIMALISM_PROTOTYPE
@@ -35,7 +40,7 @@
         /** Is the heads-up cycling animation enabled */
         @JvmStatic
         inline val isEnabled
-            get() = Flags.notificationMinimalismPrototype()
+            get() = Flags.notificationMinimalismPrototype() && version == 1
 
         /**
          * the prototype will now show seen notifications on the locked shade by default, but this
@@ -76,4 +81,45 @@
         @JvmStatic
         inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
     }
+    object V2 {
+        const val FLAG_NAME = Flags.FLAG_NOTIFICATION_MINIMALISM_PROTOTYPE
+
+        /** A token used for dependency declaration */
+        val token: FlagToken
+            get() = FlagToken(FLAG_NAME, isEnabled)
+
+        /** Is the heads-up cycling animation enabled */
+        @JvmStatic
+        inline val isEnabled
+            get() = Flags.notificationMinimalismPrototype() && version == 2
+
+        /**
+         * The prototype will (by default) use a promoter to ensure that the top unseen notification
+         * is not grouped, but this property read allows that behavior to be disabled.
+         */
+        val ungroupTopUnseen: Boolean
+            get() =
+                if (isUnexpectedlyInLegacyMode()) false
+                else
+                    SystemProperties.getBoolean(
+                        "persist.notification_minimalism_prototype.ungroup_top_unseen",
+                        true
+                    )
+
+        /**
+         * Called to ensure code is only run when the flag is enabled. This protects users from the
+         * unintended behaviors caused by accidentally running new logic, while also crashing on an
+         * eng build to ensure that the refactor author catches issues in testing.
+         */
+        @JvmStatic
+        inline fun isUnexpectedlyInLegacyMode() =
+            RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+        /**
+         * Called to ensure code is only run when the flag is disabled. This will throw an exception
+         * if the flag is enabled to ensure that the refactor author catches issues in testing.
+         */
+        @JvmStatic
+        inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt
new file mode 100644
index 0000000..472fd95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/PriorityPeopleSection.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.shared
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for com.android.systemui.Flags.FLAG_PRIORITY_PEOPLE_SECTION */
+@Suppress("NOTHING_TO_INLINE")
+object PriorityPeopleSection {
+    const val FLAG_NAME = Flags.FLAG_PRIORITY_PEOPLE_SECTION
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Are sections sorted by time? */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.priorityPeopleSection()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 92c597c..48796d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -439,6 +439,15 @@
         Trace.endSection();
     }
 
+    /**
+     * Update the expand state of the group header.
+     */
+    public void updateGroupHeaderExpandState() {
+        if (mGroupHeaderWrapper != null) {
+            mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
+        }
+    }
+
     private void removeGroupHeader() {
         if (mGroupHeader == null) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
index 31f4857..fc28a99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -3,15 +3,22 @@
 import android.annotation.IntDef
 
 /**
- * For now, declare the available notification buckets (sections) here so that other
- * presentation code can decide what to do based on an entry's buckets
+ * For now, declare the available notification buckets (sections) here so that other presentation
+ * code can decide what to do based on an entry's buckets
  */
 @Retention(AnnotationRetention.SOURCE)
 @IntDef(
-        prefix = ["BUCKET_"],
-        value = [
-            BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
-            BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
+    prefix = ["BUCKET_"],
+    value =
+        [
+            BUCKET_UNKNOWN,
+            BUCKET_MEDIA_CONTROLS,
+            BUCKET_HEADS_UP,
+            BUCKET_FOREGROUND_SERVICE,
+            BUCKET_PRIORITY_PEOPLE,
+            BUCKET_PEOPLE,
+            BUCKET_ALERTING,
+            BUCKET_SILENT
         ]
 )
 annotation class PriorityBucket
@@ -20,6 +27,7 @@
 const val BUCKET_MEDIA_CONTROLS = 1
 const val BUCKET_HEADS_UP = 2
 const val BUCKET_FOREGROUND_SERVICE = 3
+const val BUCKET_PRIORITY_PEOPLE = 7
 const val BUCKET_PEOPLE = 4
 const val BUCKET_ALERTING = 5
 const val BUCKET_SILENT = 6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index a446745..4b0b1e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -72,6 +72,9 @@
      */
     private var maxNotificationsExcludesMedia = false
 
+    /** Whether we allow keyguard to show less important notifications above the shelf. */
+    private var limitLockScreenToImportant = false
+
     /** Minimum space between two notifications, see [calculateGapAndDividerHeight]. */
     private var dividerHeight by notNull<Float>()
 
@@ -85,6 +88,14 @@
         updateResources()
     }
 
+    private fun allowedByPolicy(stackHeight: StackHeight): Boolean =
+        if (limitLockScreenToImportant && stackHeight.includesLessImportantNotification) {
+            log { "\tallowedByPolicy = false" }
+            false
+        } else {
+            true
+        }
+
     /**
      * Returns whether notifications and (shelf if visible) can fit in total space available.
      * [shelfSpace] is extra vertical space allowed for the shelf to overlap the lock icon.
@@ -183,11 +194,12 @@
         log { "\tGet maxNotifWithoutSavingSpace ---" }
         val maxNotifWithoutSavingSpace =
             stackHeightSequence.lastIndexWhile { heightResult ->
-                canStackFitInSpace(
-                    heightResult,
-                    notifSpace = notifSpace,
-                    shelfSpace = shelfSpace
-                ) == FitResult.FIT
+                allowedByPolicy(heightResult) &&
+                    canStackFitInSpace(
+                        heightResult,
+                        notifSpace = notifSpace,
+                        shelfSpace = shelfSpace
+                    ) == FitResult.FIT
             }
 
         // How many notifications we can show at heightWithoutLockscreenConstraints
@@ -212,11 +224,12 @@
             saveSpaceOnLockscreen = true
             maxNotifications =
                 stackHeightSequence.lastIndexWhile { heightResult ->
-                    canStackFitInSpace(
-                        heightResult,
-                        notifSpace = notifSpace,
-                        shelfSpace = shelfSpace
-                    ) != FitResult.NO_FIT
+                    allowedByPolicy(heightResult) &&
+                        canStackFitInSpace(
+                            heightResult,
+                            notifSpace = notifSpace,
+                            shelfSpace = shelfSpace
+                        ) != FitResult.NO_FIT
                 }
             log { "\t--- maxNotifications=$maxNotifications" }
         }
@@ -318,7 +331,10 @@
 
         // Float height of shelf (0 if shelf is not showing), and space before the shelf that
         // changes during the lockscreen <=> full shade transition.
-        val shelfHeightWithSpaceBefore: Float
+        val shelfHeightWithSpaceBefore: Float,
+
+        /** Whether this stack height includes less at least one important notification. */
+        val includesLessImportantNotification: Boolean
     )
 
     private fun computeHeightPerNotificationLimit(
@@ -331,12 +347,15 @@
         var previous: ExpandableView? = null
         val onLockscreen = onLockscreen()
 
+        var includesLessImportantNotification = false
+
         // Only shelf. This should never happen, since we allow 1 view minimum (EmptyViewState).
         yield(
             StackHeight(
                 notifsHeight = 0f,
                 notifsHeightSavingSpace = 0f,
-                shelfHeightWithSpaceBefore = shelfHeight
+                shelfHeightWithSpaceBefore = shelfHeight,
+                includesLessImportantNotification = includesLessImportantNotification,
             )
         )
 
@@ -362,6 +381,19 @@
                     spaceBeforeShelf + shelfHeight
                 }
 
+            if (limitLockScreenToImportant && !includesLessImportantNotification) {
+                val bucket = (currentNotification as? ExpandableNotificationRow)?.entry?.bucket
+                includesLessImportantNotification =
+                    when (bucket) {
+                        null,
+                        BUCKET_MEDIA_CONTROLS,
+                        BUCKET_HEADS_UP,
+                        BUCKET_FOREGROUND_SERVICE,
+                        BUCKET_PRIORITY_PEOPLE -> false
+                        else -> true
+                    }
+            }
+
             log {
                 "\tcomputeHeightPerNotificationLimit i=$i notifs=$notifications " +
                     "notifsHeightSavingSpace=$notifsWithCollapsedHun" +
@@ -371,7 +403,8 @@
                 StackHeight(
                     notifsHeight = notifications,
                     notifsHeightSavingSpace = notifsWithCollapsedHun,
-                    shelfHeightWithSpaceBefore = shelfWithSpaceBefore
+                    shelfHeightWithSpaceBefore = shelfWithSpaceBefore,
+                    includesLessImportantNotification = includesLessImportantNotification,
                 )
             )
         }
@@ -382,11 +415,16 @@
             infiniteIfNegative(
                 if (NotificationMinimalismPrototype.V1.isEnabled) {
                     NotificationMinimalismPrototype.V1.maxNotifs
+                } else if (NotificationMinimalismPrototype.V2.isEnabled) {
+                    1
                 } else {
                     resources.getInteger(R.integer.keyguard_max_notification_count)
                 }
             )
-        maxNotificationsExcludesMedia = NotificationMinimalismPrototype.V1.isEnabled
+        maxNotificationsExcludesMedia =
+            NotificationMinimalismPrototype.V1.isEnabled ||
+                NotificationMinimalismPrototype.V2.isEnabled
+        limitLockScreenToImportant = NotificationMinimalismPrototype.V2.isEnabled
 
         dividerHeight =
             max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
index dacafc4..db544ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt
@@ -38,16 +38,6 @@
      */
     val shadeScrimBounds = MutableStateFlow<ShadeScrimBounds?>(null)
 
-    /**
-     * The y-coordinate in px of top of the contents of the notification stack. This value can be
-     * negative, if the stack is scrolled such that its top extends beyond the top edge of the
-     * screen.
-     */
-    val stackTop = MutableStateFlow(0f)
-
-    /** the bottom-most acceptable y-position for the bottom of the stack / shelf */
-    val stackBottom = MutableStateFlow(0f)
-
     /** the y position of the top of the HUN area */
     val headsUpTop = MutableStateFlow(0f)
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index 365ead6..e7acbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -72,12 +72,6 @@
     val alphaForBrightnessMirror: StateFlow<Float> =
         placeholderRepository.alphaForBrightnessMirror.asStateFlow()
 
-    /** The y-coordinate in px of top of the contents of the notification stack. */
-    val stackTop: StateFlow<Float> = placeholderRepository.stackTop.asStateFlow()
-
-    /** The y-coordinate in px of bottom of the contents of the notification stack. */
-    val stackBottom: StateFlow<Float> = placeholderRepository.stackBottom.asStateFlow()
-
     /** The height of the keyguard's available space bounds */
     val constrainedAvailableSpace: StateFlow<Int> =
         placeholderRepository.constrainedAvailableSpace.asStateFlow()
@@ -121,16 +115,6 @@
         viewHeightRepository.headsUpHeight.value = height
     }
 
-    /** Sets the y-coord in px of the top of the contents of the notification stack. */
-    fun setStackTop(stackTop: Float) {
-        placeholderRepository.stackTop.value = stackTop
-    }
-
-    /** Sets the y-coord in px of the bottom of the contents of the notification stack. */
-    fun setStackBottom(stackBottom: Float) {
-        placeholderRepository.stackBottom.value = stackBottom
-    }
-
     /** Sets whether the notification stack is scrolled to the top. */
     fun setScrolledToTop(scrolledToTop: Boolean) {
         placeholderRepository.scrolledToTop.value = scrolledToTop
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 3c44713..622d8e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -79,8 +79,6 @@
         }
 
         launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
-        launch { viewModel.stackTop.collect { view.setStackTop(it) } }
-        launch { viewModel.stackBottom.collect { view.setStackBottom(it) } }
         launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
         launch { viewModel.headsUpTop.collect { view.setHeadsUpTop(it) } }
         launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 082f6b6..6137381 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -130,10 +130,6 @@
     val maxAlpha: Flow<Float> =
         stackAppearanceInteractor.alphaForBrightnessMirror.dumpValue("maxAlpha")
 
-    /** The y-coordinate in px of top of the contents of the notification stack. */
-    val stackTop: Flow<Float> = stackAppearanceInteractor.stackTop.dumpValue("stackTop")
-    /** The y-coordinate in px of bottom of the contents of the notification stack. */
-    val stackBottom: Flow<Float> = stackAppearanceInteractor.stackBottom.dumpValue("stackBottom")
     /**
      * Whether the notification stack is scrolled to the top; i.e., it cannot be scrolled down any
      * further.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
index 736058a..97b86e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
-import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlagsClassic
@@ -57,18 +56,6 @@
         interactor.setShadeScrimBounds(bounds)
     }
 
-    /** Notifies that the bounds of the notification placeholder have changed. */
-    fun onStackBoundsChanged(
-        top: Float,
-        bottom: Float,
-    ) {
-        keyguardInteractor.setNotificationContainerBounds(
-            NotificationContainerBounds(top = top, bottom = bottom)
-        )
-        interactor.setStackTop(top)
-        interactor.setStackBottom(bottom)
-    }
-
     /** Sets the available space */
     fun onConstrainedAvailableSpaceChanged(height: Int) {
         interactor.setConstrainedAvailableSpace(height)
diff --git a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
new file mode 100644
index 0000000..efeb2f9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
@@ -0,0 +1,322 @@
+/*
+ * 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.theme;
+
+import com.google.ux.material.libmonet.dynamiccolor.ContrastCurve;
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
+import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
+import com.google.ux.material.libmonet.dynamiccolor.ToneDeltaPair;
+import com.google.ux.material.libmonet.dynamiccolor.TonePolarity;
+
+class CustomDynamicColors {
+    private final MaterialDynamicColors mMdc;
+
+    CustomDynamicColors(boolean isExtendedFidelity) {
+        this.mMdc = new MaterialDynamicColors(isExtendedFidelity);
+    }
+
+    // CLOCK COLORS
+
+    public DynamicColor widgetBackground() {
+        return new DynamicColor(
+                /* name= */ "widget_background",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 20.0 : 95.0,
+                /* isBackground= */ true,
+                /* background= */ null,
+                /* secondBackground= */ null,
+                /* contrastCurve= */ null,
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor clockHour() {
+        return new DynamicColor(
+                /* name= */ "clock_hour",
+                /* palette= */ (s) -> s.secondaryPalette,
+                /* tone= */ (s) -> s.isDark ? 30.0 : 60.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> widgetBackground(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 4.0, 5.0, 15.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(clockHour(), clockMinute(), 10.0, TonePolarity.DARKER,
+                        false));
+    }
+
+    public DynamicColor clockMinute() {
+        return new DynamicColor(
+                /* name= */ "clock_minute",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> widgetBackground(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 6.5, 10.0, 15.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor clockSecond() {
+        return new DynamicColor(
+                /* name= */ "clock_second",
+                /* palette= */ (s) -> s.tertiaryPalette,
+                /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> widgetBackground(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor weatherTemp() {
+        return new DynamicColor(
+                /* name= */ "clock_second",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 55.0 : 80.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> widgetBackground(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    // THEME APP ICONS
+
+    public DynamicColor themeApp() {
+        return new DynamicColor(
+                /* name= */ "theme_app",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 90.0 : 30.0, // Adjusted values
+                /* isBackground= */ true,
+                /* background= */ null,
+                /* secondBackground= */ null,
+                /* contrastCurve= */ null,
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor onThemeApp() {
+        return new DynamicColor(
+                /* name= */ "on_theme_app",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, // Adjusted values
+                /* isBackground= */ false,
+                /* background= */ (s) -> themeApp(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 10.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor themeAppRing() {
+        return new DynamicColor(
+                /* name= */ "theme_app_ring",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> 70.0,
+                /* isBackground= */ true,
+                /* background= */ null,
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor themeNotif() {
+        return new DynamicColor(
+                /* name= */ "theme_notif",
+                /* palette= */ (s) -> s.tertiaryPalette,
+                /* tone= */ (s) -> s.isDark ? 80.0 : 90.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> themeAppRing(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(themeNotif(), themeAppRing(), 10.0, TonePolarity.NEARER,
+                        false));
+    }
+
+    // SUPER G COLORS
+
+    public DynamicColor brandA() {
+        return new DynamicColor(
+                /* name= */ "brand_a",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 40.0 : 80.0,
+                /* isBackground= */ true,
+                /* background= */ (s) -> mMdc.surfaceContainerLow(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 17.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(brandA(), brandB(), 10.0, TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor brandB() {
+        return new DynamicColor(
+                /* name= */ "brand_b",
+                /* palette= */ (s) -> s.secondaryPalette,
+                /* tone= */ (s) -> s.isDark ? 70.0 : 98.0,
+                /* isBackground= */ true,
+                /* background= */ (s) -> mMdc.surfaceContainerLow(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 3.0, 6.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(brandB(), brandC(), 10.0, TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor brandC() {
+        return new DynamicColor(
+                /* name= */ "brand_c",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> s.isDark ? 50.0 : 60.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> mMdc.surfaceContainerLow(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 9.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(brandC(), brandD(), 10.0, TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor brandD() {
+        return new DynamicColor(
+                /* name= */ "brand_d",
+                /* palette= */ (s) -> s.tertiaryPalette,
+                /* tone= */ (s) -> s.isDark ? 59.0 : 90.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> mMdc.surfaceContainerLow(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 13.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(brandD(), brandA(), 10.0, TonePolarity.NEARER, false));
+    }
+
+    // QUICK SETTING TIILES
+
+    public DynamicColor underSurface() {
+        return new DynamicColor(
+                /* name= */ "under_surface",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> 0.0,
+                /* isBackground= */ true,
+                /* background= */ null,
+                /* secondBackground= */ null,
+                /* contrastCurve= */ null,
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor shadeActive() {
+        return new DynamicColor(
+                /* name= */ "shade_active",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> 90.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> underSurface(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.5, 7.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(shadeActive(), shadeInactive(), 30.0, TonePolarity.LIGHTER,
+                        false));
+    }
+
+    public DynamicColor onShadeActive() {
+        return new DynamicColor(
+                /* name= */ "on_shade_active",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> 10.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> shadeActive(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(onShadeActive(), onShadeActiveVariant(), 20.0,
+                        TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor onShadeActiveVariant() {
+        return new DynamicColor(
+                /* name= */ "on_shade_active_variant",
+                /* palette= */ (s) -> s.primaryPalette,
+                /* tone= */ (s) -> 30.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> shadeActive(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(onShadeActiveVariant(), onShadeActive(), 20.0,
+                        TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor shadeInactive() {
+        return new DynamicColor(
+                /* name= */ "shade_inactive",
+                /* palette= */ (s) -> s.neutralPalette,
+                /* tone= */ (s) -> 20.0,
+                /* isBackground= */ true,
+                /* background= */ (s) -> underSurface(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+                /* toneDeltaPair= */(s) -> new ToneDeltaPair(shadeInactive(), shadeDisabled(), 15.0,
+                TonePolarity.LIGHTER, false));
+    }
+
+    public DynamicColor onShadeInactive() {
+        return new DynamicColor(
+                /* name= */ "on_shade_inactive",
+                /* palette= */ (s) -> s.neutralVariantPalette,
+                /* tone= */ (s) -> 90.0,
+                /* isBackground= */ true,
+                /* background= */ (s) -> shadeInactive(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(onShadeInactive(), onShadeInactiveVariant(), 10.0,
+                        TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor onShadeInactiveVariant() {
+        return new DynamicColor(
+                /* name= */ "on_shade_inactive_variant",
+                /* palette= */ (s) -> s.neutralVariantPalette,
+                /* tone= */ (s) -> 80.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> shadeInactive(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
+                /* toneDeltaPair= */
+                (s) -> new ToneDeltaPair(onShadeInactiveVariant(), onShadeInactive(), 10.0,
+                        TonePolarity.NEARER, false));
+    }
+
+    public DynamicColor shadeDisabled() {
+        return new DynamicColor(
+                /* name= */ "shade_disabled",
+                /* palette= */ (s) -> s.neutralPalette,
+                /* tone= */ (s) -> 4.0,
+                /* isBackground= */ false,
+                /* background= */ (s) -> underSurface(),
+                /* secondBackground= */ null,
+                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
+                /* toneDeltaPair= */ null);
+    }
+
+    public DynamicColor overviewBackground() {
+        return new DynamicColor(
+                /* name= */ "overview_background",
+                /* palette= */ (s) -> s.neutralVariantPalette,
+                /* tone= */ (s) -> s.isDark ? 80.0 : 35.0,
+                /* isBackground= */ true,
+                /* background= */ null,
+                /* secondBackground= */ null,
+                /* contrastCurve= */null,
+                /* toneDeltaPair= */ null);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index a983d2f..3518759 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -103,5 +103,33 @@
                 Pair.create("on_tertiary_fixed_variant", mdc.onTertiaryFixedVariant()),
             )
         }
+
+        @JvmStatic
+        fun getCustomColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
+            val customMdc = CustomDynamicColors(isExtendedFidelity)
+            return arrayListOf(
+                Pair.create("widget_background", customMdc.widgetBackground()),
+                Pair.create("clock_hour", customMdc.clockHour()),
+                Pair.create("clock_minute", customMdc.clockMinute()),
+                Pair.create("clock_second", customMdc.weatherTemp()),
+                Pair.create("theme_app", customMdc.themeApp()),
+                Pair.create("on_theme_app", customMdc.onThemeApp()),
+                Pair.create("theme_app_ring", customMdc.themeAppRing()),
+                Pair.create("on_theme_app_ring", customMdc.themeNotif()),
+                Pair.create("brand_a", customMdc.brandA()),
+                Pair.create("brand_b", customMdc.brandB()),
+                Pair.create("brand_c", customMdc.brandC()),
+                Pair.create("brand_d", customMdc.brandD()),
+                Pair.create("under_surface", customMdc.underSurface()),
+                Pair.create("shade_active", customMdc.shadeActive()),
+                Pair.create("on_shade_active", customMdc.onShadeActive()),
+                Pair.create("on_shade_active_variant", customMdc.onShadeActiveVariant()),
+                Pair.create("shade_inactive", customMdc.shadeInactive()),
+                Pair.create("on_shade_inactive", customMdc.onShadeInactive()),
+                Pair.create("on_shade_inactive_variant", customMdc.onShadeInactiveVariant()),
+                Pair.create("shade_disabled", customMdc.shadeDisabled()),
+                Pair.create("overview_background", customMdc.overviewBackground())
+            )
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 5c3bbb7..d256c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -56,6 +56,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
@@ -84,6 +85,7 @@
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.SecureSettings;
 
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
 import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
 
 import org.json.JSONException;
@@ -631,29 +633,33 @@
 
     protected FabricatedOverlay createDynamicOverlay() {
         FabricatedOverlay overlay = newFabricatedOverlay("dynamic");
-        assignDynamicPaletteToOverlay(overlay, true /* isDark */);
-        assignDynamicPaletteToOverlay(overlay, false /* isDark */);
-        assignFixedColorsToOverlay(overlay);
+        //Themed Colors
+        assignColorsToOverlay(overlay, DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled),
+                false);
+        // Fixed Colors
+        assignColorsToOverlay(overlay, DynamicColors.getFixedColorsMapped(mIsFidelityEnabled),
+                true);
+        //Custom Colors
+        assignColorsToOverlay(overlay, DynamicColors.getCustomColorsMapped(mIsFidelityEnabled),
+                false);
         return overlay;
     }
 
-    private void assignDynamicPaletteToOverlay(FabricatedOverlay overlay, boolean isDark) {
-        String suffix = isDark ? "dark" : "light";
-        ColorScheme scheme = isDark ? mDarkColorScheme : mLightColorScheme;
-        DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled).forEach(p -> {
-            String resourceName = "android:color/system_" + p.first + "_" + suffix;
-            int colorValue = p.second.getArgb(scheme.getMaterialScheme());
-            overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
-                    null /* configuration */);
-        });
-    }
+    private void assignColorsToOverlay(FabricatedOverlay overlay,
+            List<Pair<String, DynamicColor>> colors, Boolean isFixed) {
+        colors.forEach(p -> {
+            String prefix = "android:color/system_" + p.first;
 
-    private void assignFixedColorsToOverlay(FabricatedOverlay overlay) {
-        DynamicColors.getFixedColorsMapped(mIsFidelityEnabled).forEach(p -> {
-            String resourceName = "android:color/system_" + p.first;
-            int colorValue = p.second.getArgb(mLightColorScheme.getMaterialScheme());
-            overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
-                    null /* configuration */);
+            if (isFixed) {
+                overlay.setResourceValue(prefix, TYPE_INT_COLOR_ARGB8,
+                        p.second.getArgb(mLightColorScheme.getMaterialScheme()), null);
+                return;
+            }
+
+            overlay.setResourceValue(prefix + "_light", TYPE_INT_COLOR_ARGB8,
+                    p.second.getArgb(mLightColorScheme.getMaterialScheme()), null);
+            overlay.setResourceValue(prefix + "_dark", TYPE_INT_COLOR_ARGB8,
+                    p.second.getArgb(mDarkColorScheme.getMaterialScheme()), null);
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
index bfed0c4..0a1724c 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -70,8 +70,10 @@
     val isGuestUserResetting: Boolean = repository.isGuestUserResetting
 
     init {
-        resumeSessionReceiver.register()
-        resetOrExitSessionReceiver.register()
+        if (applicationContext.userId == UserHandle.USER_SYSTEM) {
+            resumeSessionReceiver.register()
+            resetOrExitSessionReceiver.register()
+        }
     }
 
     /** Notifies that the device has finished booting. */
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 46ce5f2..1ec86a4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -97,3 +97,12 @@
 fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> {
     return combine(flow1, flow2, bifunction)
 }
+
+fun <A, B, C, R> combineFlows(
+    flow1: Flow<A>,
+    flow2: Flow<B>,
+    flow3: Flow<C>,
+    trifunction: (A, B, C) -> R
+): Flow<R> {
+    return combine(flow1, flow2, flow3, trifunction)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
index d0d9891..8a5af09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt
@@ -40,7 +40,6 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.runner.RunWith
 
 @SmallTest
@@ -1149,7 +1148,6 @@
      *
      * In STL there is no guarantee that transitions settle in Idle before continuing.
      */
-    @Ignore("Suffers from a race condition that will be fixed in followup CL")
     @Test
     fun transition_from_ls_scene_interrupted_by_other_from_ls_transition() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
index 9f0e67b..85cc88d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
@@ -15,11 +15,13 @@
  */
 package com.android.systemui.monet
 
-import androidx.test.filters.SmallTest
 import android.testing.AndroidTestingRunner
 import android.util.Log
+import android.util.Pair
+import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.theme.DynamicColors
+import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
 import com.google.ux.material.libmonet.hct.Hct
 import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
 import java.io.File
@@ -81,6 +83,10 @@
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 class ColorSchemeTest : SysuiTestCase() {
+    private val defaultContrast = 0.0
+    private val defaultIsDark = false
+    private val defaultIsFidelity = false
+
     @Test
     fun generateThemeStyles() {
         val document = buildDoc<Any>()
@@ -107,7 +113,7 @@
                 }
 
                 val style = document.createElement(styleValue.name.lowercase())
-                val colorScheme = ColorScheme(sourceColor.toInt(), false, styleValue)
+                val colorScheme = ColorScheme(sourceColor.toInt(), defaultIsDark, styleValue)
 
                 style.appendChild(
                     document.createTextNode(
@@ -139,7 +145,7 @@
         document.appendWithBreak(resources)
 
         // shade colors
-        val colorScheme = ColorScheme(GOOGLE_BLUE, false)
+        val colorScheme = ColorScheme(GOOGLE_BLUE, defaultIsDark)
         arrayOf(
                 Triple("accent1", "Primary", colorScheme.accent1),
                 Triple("accent2", "Secondary", colorScheme.accent2),
@@ -162,24 +168,35 @@
 
         resources.appendWithBreak(document.createComment(commentRoles), 2)
 
-        // dynamic colors
-        arrayOf(false, true).forEach { isDark ->
-            val suffix = if (isDark) "_dark" else "_light"
-            val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, 0.5)
-            DynamicColors.allDynamicColorsMapped(false).forEach {
-                resources.createColorEntry(
-                    "system_${it.first}$suffix",
-                    it.second.getArgb(dynamicScheme)
-                )
+        fun generateDynamic(pairs: List<Pair<String, DynamicColor>>) {
+            arrayOf(false, true).forEach { isDark ->
+                val suffix = if (isDark) "_dark" else "_light"
+                val dynamicScheme =
+                    SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, defaultContrast)
+                pairs.forEach {
+                    resources.createColorEntry(
+                        "system_${it.first}$suffix",
+                        it.second.getArgb(dynamicScheme)
+                    )
+                }
             }
         }
 
+        // dynamic colors
+        generateDynamic(DynamicColors.allDynamicColorsMapped(defaultIsFidelity))
+
         // fixed colors
-        val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), false, 0.5)
-        DynamicColors.getFixedColorsMapped(false).forEach {
+        val dynamicScheme =
+            SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), defaultIsDark, defaultContrast)
+        DynamicColors.getFixedColorsMapped(defaultIsFidelity).forEach {
             resources.createColorEntry("system_${it.first}", it.second.getArgb(dynamicScheme))
         }
 
+        resources.appendWithBreak(document.createComment(commentRoles), 2)
+
+        // custom colors
+        generateDynamic(DynamicColors.getCustomColorsMapped(defaultIsFidelity))
+
         saveFile(document, "role_values.xml")
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
index 5e53fe1..5cd3f66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
@@ -23,17 +23,18 @@
 import android.testing.TestableContext
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.proxy.SystemUiProxy
 import com.android.systemui.settings.DisplayTracker
 import com.android.systemui.shared.system.ActivityManagerWrapper
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestCoroutineScheduler
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.verify
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
 
 @RunWith(AndroidTestingRunner::class)
 class ActionIntentExecutorTest : SysuiTestCase() {
@@ -44,8 +45,9 @@
     private val testableContext = TestableContext(mContext)
 
     private val activityManagerWrapper = mock<ActivityManagerWrapper>()
+    private val systemUiProxy = mock<SystemUiProxy>()
+
     private val displayTracker = mock<DisplayTracker>()
-    private val keyguardController = mock<ScreenshotKeyguardController>()
 
     private val actionIntentExecutor =
         ActionIntentExecutor(
@@ -53,12 +55,12 @@
             activityManagerWrapper,
             testScope,
             mainDispatcher,
+            systemUiProxy,
             displayTracker,
-            keyguardController,
         )
 
     @Test
-    @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS)
+    @EnableFlags(Flags.FLAG_FIX_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS)
     fun launchIntent_callsCloseSystemWindows() =
         testScope.runTest {
             val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index ed7c956..a5e7a67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -995,9 +995,11 @@
                 .setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
         // All dynamic colors were added twice: light and dark them
         // All fixed colors were added once
+        // All custom dynamic tokens added twice
         verify(dynamic, times(
                 DynamicColors.allDynamicColorsMapped(false).size() * 2
-                        + DynamicColors.getFixedColorsMapped(false).size())
+                        + DynamicColors.getFixedColorsMapped(false).size()
+                        + DynamicColors.getCustomColorsMapped(false).size() * 2)
         ).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 948670f..01795e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.user.domain.interactor
 
 import android.app.admin.DevicePolicyManager
+import android.content.Context
 import android.content.pm.UserInfo
 import android.os.UserHandle
 import android.os.UserManager
@@ -59,6 +60,7 @@
     @Mock private lateinit var switchUser: (Int) -> Unit
     @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
     @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
+    @Mock private lateinit var otherContext: Context
 
     private lateinit var underTest: GuestUserInteractor
 
@@ -74,28 +76,30 @@
         repository = FakeUserRepository()
         repository.setUserInfos(ALL_USERS)
 
-        underTest =
-            GuestUserInteractor(
-                applicationContext = context,
-                applicationScope = scope,
-                mainDispatcher = IMMEDIATE,
-                backgroundDispatcher = IMMEDIATE,
-                manager = manager,
-                repository = repository,
-                deviceProvisionedController = deviceProvisionedController,
-                devicePolicyManager = devicePolicyManager,
-                refreshUsersScheduler =
-                    RefreshUsersScheduler(
-                        applicationScope = scope,
-                        mainDispatcher = IMMEDIATE,
-                        repository = repository,
-                    ),
-                uiEventLogger = uiEventLogger,
-                resumeSessionReceiver = resumeSessionReceiver,
-                resetOrExitSessionReceiver = resetOrExitSessionReceiver,
-            )
+        underTest = initGuestUserInteractor(context)
     }
 
+    private fun initGuestUserInteractor(context: Context) =
+        GuestUserInteractor(
+            applicationContext = context,
+            applicationScope = scope,
+            mainDispatcher = IMMEDIATE,
+            backgroundDispatcher = IMMEDIATE,
+            manager = manager,
+            repository = repository,
+            deviceProvisionedController = deviceProvisionedController,
+            devicePolicyManager = devicePolicyManager,
+            refreshUsersScheduler =
+                RefreshUsersScheduler(
+                    applicationScope = scope,
+                    mainDispatcher = IMMEDIATE,
+                    repository = repository,
+                ),
+            uiEventLogger = uiEventLogger,
+            resumeSessionReceiver = resumeSessionReceiver,
+            resetOrExitSessionReceiver = resetOrExitSessionReceiver,
+        )
+
     @Test
     fun registersBroadcastReceivers() {
         verify(resumeSessionReceiver).register()
@@ -103,6 +107,16 @@
     }
 
     @Test
+    fun registersBroadcastReceiversOnlyForSystemUser() {
+        for (i in 1..5) {
+            whenever(otherContext.userId).thenReturn(UserHandle.MIN_SECONDARY_USER_ID + i)
+            initGuestUserInteractor(otherContext)
+        }
+        verify(resumeSessionReceiver).register()
+        verify(resetOrExitSessionReceiver).register()
+    }
+
+    @Test
     fun onDeviceBootCompleted_allowedToAdd_createGuest() =
         runBlocking(IMMEDIATE) {
             setAllowedToAdd()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 2bd584e..562ac0c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -27,6 +27,8 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.logging.InstanceId;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SbnBuilder;
@@ -36,6 +38,7 @@
 import kotlin.Unit;
 
 import java.util.ArrayList;
+import java.util.function.Consumer;
 
 /**
  * Combined builder for constructing a NotificationEntry and its associated StatusBarNotification
@@ -73,6 +76,20 @@
         mCreationTime = source.getCreationTime();
     }
 
+    /** Allows the caller to sub-build the ranking */
+    @NonNull
+    public NotificationEntryBuilder updateRanking(@NonNull Consumer<RankingBuilder> rankingUpdater) {
+        rankingUpdater.accept(mRankingBuilder);
+        return this;
+    }
+
+    /** Allows the caller to sub-build the SBN */
+    @NonNull
+    public NotificationEntryBuilder updateSbn(@NonNull Consumer<SbnBuilder> sbnUpdater) {
+        sbnUpdater.accept(mSbnBuilder);
+        return this;
+    }
+
     /** Update an the parent on an existing entry */
     public static void setNewParent(NotificationEntry entry, GroupEntry parent) {
         entry.setParent(parent);
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index bc608c5..95cbb6b 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -221,7 +221,9 @@
     data: [
         ":framework-minus-apex.ravenwood.stats",
         ":framework-minus-apex.ravenwood.apis",
+        ":framework-minus-apex.ravenwood.keep_all",
         ":services.core.ravenwood.stats",
         ":services.core.ravenwood.apis",
+        ":services.core.ravenwood.keep_all",
     ],
 }
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
index cf58bd2..43b61a4 100755
--- a/ravenwood/scripts/ravenwood-stats-collector.sh
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -18,8 +18,14 @@
 set -e
 
 # Output files
-stats=/tmp/ravenwood-stats-all.csv
-apis=/tmp/ravenwood-apis-all.csv
+out_dir=/tmp/ravenwood
+stats=$out_dir/ravenwood-stats-all.csv
+apis=$out_dir/ravenwood-apis-all.csv
+keep_all_dir=$out_dir/ravenwood-keep-all/
+
+rm -fr $out_dir
+mkdir -p $out_dir
+mkdir -p $keep_all_dir
 
 # Where the input files are.
 path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
@@ -76,3 +82,7 @@
 
 collect_stats $stats
 collect_apis $apis
+
+cp *keep_all.txt $keep_all_dir
+echo "Keep all files created at:"
+find $keep_all_dir -type f
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index 0e66fbc..71a1822 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -23,6 +23,7 @@
 import android.os.Build;
 import android.util.Slog;
 
+import com.google.security.cryptauth.lib.securegcm.ukey2.AlertException;
 import com.google.security.cryptauth.lib.securegcm.ukey2.BadHandleException;
 import com.google.security.cryptauth.lib.securegcm.ukey2.CryptoException;
 import com.google.security.cryptauth.lib.securegcm.ukey2.D2DConnectionContextV1;
@@ -203,7 +204,8 @@
      *
      * This method must only be called from one of the two participants.
      */
-    public void establishSecureConnection() throws IOException, SecureChannelException {
+    public void establishSecureConnection() throws IOException,
+            SecureChannelException, HandshakeException {
         if (isSecured()) {
             Slog.d(TAG, "Channel is already secure.");
             return;
@@ -334,7 +336,7 @@
         }
     }
 
-    private void initiateHandshake() throws IOException, BadHandleException {
+    private void initiateHandshake() throws IOException, BadHandleException , HandshakeException {
         if (mConnectionContext != null) {
             Slog.d(TAG, "Ukey2 handshake is already completed.");
             return;
@@ -394,8 +396,8 @@
         }
     }
 
-    private void exchangeHandshake()
-            throws IOException, HandshakeException, BadHandleException, CryptoException {
+    private void exchangeHandshake() throws IOException, HandshakeException,
+            BadHandleException, CryptoException, AlertException {
         if (mConnectionContext != null) {
             Slog.d(TAG, "Ukey2 handshake is already completed.");
             return;
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index 9a73a2d..f5db6e9 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -27,9 +27,9 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
-import static com.android.server.contextualsearch.flags.Flags.enableExcludePersistentUi;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
 
@@ -286,13 +286,11 @@
         }
         final ScreenCapture.ScreenshotHardwareBuffer shb;
         if (mWmInternal != null) {
-            if (enableExcludePersistentUi()) {
-                shb = mWmInternal.takeAssistScreenshot(
-                        Set.of(TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL));
-            } else {
-                shb = mWmInternal.takeAssistScreenshot(/* windowTypesToExclude= */ Set.of());
-            }
-
+            shb = mWmInternal.takeAssistScreenshot(Set.of(
+                    TYPE_STATUS_BAR,
+                    TYPE_NAVIGATION_BAR,
+                    TYPE_NAVIGATION_BAR_PANEL,
+                    TYPE_POINTER));
         } else {
             shb = null;
         }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 94bf813..9be0e1f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3783,6 +3783,14 @@
         return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime());
     }
 
+    private TimeLimitedFgsInfo getFgsTimeLimitedInfo(int uid, int fgsType) {
+        final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(uid);
+        if (fgsInfo != null) {
+            return fgsInfo.get(fgsType);
+        }
+        return null;
+    }
+
     private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) {
         final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType);
         if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
@@ -3793,16 +3801,12 @@
 
         if (previouslyTimeLimitedType != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) {
             // FGS is switching types and the previous type was time-limited so update the runtime.
-            final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
-            if (fgsInfo != null) {
-                final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(previouslyTimeLimitedType);
-                if (fgsTypeInfo != null) {
-                    // Update the total runtime for the previous time-limited fgs type.
-                    fgsTypeInfo.updateTotalRuntime();
-                    // TODO(b/330399444): handle the case where an app is running 2 services of the
-                    //  same time-limited type in parallel and stops one of them which leads to the
-                    //  second running one gaining additional runtime.
-                }
+            final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+                                                    sr.appInfo.uid, previouslyTimeLimitedType);
+            if (fgsTypeInfo != null) {
+                // Update the total runtime for the previous time-limited fgs type.
+                fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+                fgsTypeInfo.decNumParallelServices();
             }
 
             if (!sr.isFgsTimeLimited()) {
@@ -3825,10 +3829,10 @@
         final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType);
         TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType);
         if (fgsTypeInfo == null) {
-            fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime);
+            fgsTypeInfo = sr.createTimeLimitedFgsInfo();
             fgsInfo.put(timeLimitedFgsType, fgsTypeInfo);
         }
-        fgsTypeInfo.setLastFgsStartTime(nowUptime);
+        fgsTypeInfo.noteFgsFgsStart(nowUptime);
 
         // We'll cancel the previous ANR timer and start a fresh one below.
         mFGSAnrTimer.cancel(sr);
@@ -3852,13 +3856,12 @@
             return; // if the current fgs type is not time-limited, return.
         }
 
-        final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
-        if (fgsInfo != null) {
-            final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedType);
-            if (fgsTypeInfo != null) {
-                // Update the total runtime for the previous time-limited fgs type.
-                fgsTypeInfo.updateTotalRuntime();
-            }
+        final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(
+                                                sr.appInfo.uid, timeLimitedType);
+        if (fgsTypeInfo != null) {
+            // Update the total runtime for the previous time-limited fgs type.
+            fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis());
+            fgsTypeInfo.decNumParallelServices();
         }
         Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr);
         mFGSAnrTimer.cancel(sr);
@@ -3913,24 +3916,21 @@
             mFGSAnrTimer.accept(sr);
             traceInstant("FGS timed out: ", sr);
 
-            final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid);
-            if (fgsInfo != null) {
-                final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType);
-                if (fgsTypeInfo != null) {
-                    // Update total runtime for the time-limited fgs type and mark it as timed out.
-                    fgsTypeInfo.updateTotalRuntime();
-                    fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
+            final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType);
+            if (fgsTypeInfo != null) {
+                // Update total runtime for the time-limited fgs type and mark it as timed out.
+                fgsTypeInfo.updateTotalRuntime(nowUptime);
+                fgsTypeInfo.setTimeLimitExceededAt(nowUptime);
 
-                    logFGSStateChangeLocked(sr,
-                            FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
-                            nowUptime > fgsTypeInfo.getLastFgsStartTime()
-                                    ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0,
-                            FGS_STOP_REASON_UNKNOWN,
-                            FGS_TYPE_POLICY_CHECK_UNKNOWN,
-                            FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA,
-                            false /* fgsRestrictionRecalculated */
-                    );
-                }
+                logFGSStateChangeLocked(sr,
+                        FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT,
+                        nowUptime > fgsTypeInfo.getFirstFgsStartUptime()
+                                ? (int) (nowUptime - fgsTypeInfo.getFirstFgsStartUptime()) : 0,
+                        FGS_STOP_REASON_UNKNOWN,
+                        FGS_TYPE_POLICY_CHECK_UNKNOWN,
+                        FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA,
+                        false /* fgsRestrictionRecalculated */
+                );
             }
 
             try {
@@ -3949,6 +3949,16 @@
         if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) {
             return; // no timed out FGS type was found (either it was stopped or it switched types)
         }
+
+        synchronized (mAm) {
+            final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType);
+            if (fgsTypeInfo != null) {
+                // Runtime is already updated when the service times out - if the app didn't
+                // stop the service, decrement the number of parallel running services here.
+                fgsTypeInfo.decNumParallelServices();
+            }
+        }
+
         final String reason = "A foreground service of type "
                 + ServiceInfo.foregroundServiceTypeToLabel(fgsType)
                 + " did not stop within its timeout: " + sr.getComponentName();
@@ -3958,7 +3968,6 @@
             Slog.wtf(TAG, reason);
             return;
         }
-
         if (android.app.Flags.enableFgsTimeoutCrashBehavior()) {
             // Crash the app
             synchronized (mAm) {
@@ -4005,7 +4014,6 @@
 
     private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) {
         maybeStopShortFgsTimeoutLocked(service);
-        maybeStopFgsTimeoutLocked(service);
         final ProcessServiceRecord psr = service.app.mServices;
         psr.stopService(service);
         psr.updateBoundClientUids();
@@ -6291,7 +6299,6 @@
             Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r);
             maybeStopShortFgsTimeoutLocked(r);
         }
-        maybeStopFgsTimeoutLocked(r);
 
         // Report to all of the connections that the service is no longer
         // available.
@@ -6416,7 +6423,6 @@
         final boolean exitingFg = r.isForeground;
         if (exitingFg) {
             maybeStopShortFgsTimeoutLocked(r);
-            maybeStopFgsTimeoutLocked(r);
             decActiveForegroundAppLocked(smap, r);
             synchronized (mAm.mProcessStats.mLock) {
                 ServiceState stracker = r.getTracker();
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 8eca4fc..2184340 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -690,10 +690,14 @@
         private long mTimeLimitExceededAt = Long.MIN_VALUE;
         @UptimeMillisLong
         private long mTotalRuntime = 0;
+        private int mNumParallelServices = 0;
 
-        TimeLimitedFgsInfo(@UptimeMillisLong long startTime) {
-            mFirstFgsStartUptime = startTime;
-            mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+        public void noteFgsFgsStart(@UptimeMillisLong long startTime) {
+            mNumParallelServices++;
+            if (mNumParallelServices == 1) {
+                mFirstFgsStartUptime = startTime;
+                mFirstFgsStartRealtime = SystemClock.elapsedRealtime();
+            }
             mLastFgsStartTime = startTime;
         }
 
@@ -707,17 +711,23 @@
             return mFirstFgsStartRealtime;
         }
 
-        public void setLastFgsStartTime(@UptimeMillisLong long startTime) {
-            mLastFgsStartTime = startTime;
-        }
-
         @UptimeMillisLong
         public long getLastFgsStartTime() {
             return mLastFgsStartTime;
         }
 
-        public void updateTotalRuntime() {
-            mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime;
+        public void decNumParallelServices() {
+            if (mNumParallelServices > 0) {
+                mNumParallelServices--;
+            }
+            if (mNumParallelServices == 0) {
+                mLastFgsStartTime = 0;
+            }
+        }
+
+        public void updateTotalRuntime(@UptimeMillisLong long nowUptime) {
+            mTotalRuntime += nowUptime - mLastFgsStartTime;
+            mLastFgsStartTime = nowUptime;
         }
 
         @UptimeMillisLong
@@ -735,6 +745,7 @@
         }
 
         public void reset() {
+            mNumParallelServices = 0;
             mFirstFgsStartUptime = 0;
             mFirstFgsStartRealtime = 0;
             mLastFgsStartTime = 0;
@@ -1872,8 +1883,8 @@
     /**
      * Called when a time-limited FGS starts.
      */
-    public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) {
-        return new TimeLimitedFgsInfo(nowUptime);
+    public TimeLimitedFgsInfo createTimeLimitedFgsInfo() {
+        return new TimeLimitedFgsInfo();
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index d9c3ab8..30d12e6 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -1189,7 +1189,11 @@
         update();
     }
 
-    void switchMode(@AutomaticBrightnessMode int mode) {
+    /**
+     * Responsible for switching the AutomaticBrightnessMode of the associated display. Also takes
+     * care of resetting the short term model wherever required
+     */
+    public void switchMode(@AutomaticBrightnessMode int mode) {
         if (!mBrightnessMappingStrategyMap.contains(mode)) {
             return;
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 70a1014..875fd05 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -84,6 +84,7 @@
 import com.android.server.display.brightness.DisplayBrightnessController;
 import com.android.server.display.brightness.clamper.BrightnessClamperController;
 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
+import com.android.server.display.brightness.strategy.DisplayBrightnessStrategyConstants;
 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
 import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
 import com.android.server.display.config.HysteresisLevels;
@@ -1333,12 +1334,6 @@
                 mDisplayStateController.shouldPerformScreenOffTransition());
         state = mPowerState.getScreenState();
 
-        // Switch to doze auto-brightness mode if needed
-        if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
-                && !mAutomaticBrightnessController.isInIdleMode()) {
-            mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
-                    ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
-        }
 
         DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController
                 .updateBrightness(mPowerRequest, state);
@@ -1372,6 +1367,13 @@
         final boolean wasShortTermModelActive =
                 mAutomaticBrightnessStrategy.isShortTermModelActive();
         if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
+            // Switch to doze auto-brightness mode if needed
+            if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
+                    && !mAutomaticBrightnessController.isInIdleMode()) {
+                mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
+                        ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+            }
+
             mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
                     mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
                     mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
@@ -1440,45 +1442,52 @@
             brightnessState = clampScreenBrightness(brightnessState);
         }
 
-        // If there's an offload session, we need to set the initial doze brightness before
-        // the offload session starts controlling the brightness.
-        // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
-        // will be selected again, meaning that no new brightness will be sent to the hardware and
-        // the display will stay at the brightness level set by the offload session.
-        if (Float.isNaN(brightnessState) && mFlags.isDisplayOffloadEnabled()
-                && Display.isDozeState(state) && mDisplayOffloadSession != null) {
-            if (mAutomaticBrightnessController != null
-                    && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
-                // Use the auto-brightness curve and the last observed lux
-                rawBrightnessState = mAutomaticBrightnessController
-                        .getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                                mTempBrightnessEvent);
-            } else {
-                rawBrightnessState = getDozeBrightnessForOffload();
-                mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
-                        | BrightnessEvent.FLAG_DOZE_SCALE);
-            }
-
-            if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
-                brightnessState = clampScreenBrightness(rawBrightnessState);
-                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
-
+        if (Display.isDozeState(state)) {
+            // If there's an offload session, we need to set the initial doze brightness before
+            // the offload session starts controlling the brightness.
+            // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
+            // will be selected again, meaning that no new brightness will be sent to the hardware
+            // and the display will stay at the brightness level set by the offload session.
+            if ((Float.isNaN(brightnessState)
+                    || displayBrightnessState.getDisplayBrightnessStrategyName()
+                    .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME))
+                    && mFlags.isDisplayOffloadEnabled()
+                    && mDisplayOffloadSession != null) {
                 if (mAutomaticBrightnessController != null
                         && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
-                    // Keep the brightness in the setting so that we can use it after the screen
-                    // turns on, until a lux sample becomes available. We don't do this when
-                    // auto-brightness is disabled - in that situation we still want to use
-                    // the last brightness from when the screen was on.
-                    updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+                    // Use the auto-brightness curve and the last observed lux
+                    rawBrightnessState = mAutomaticBrightnessController
+                            .getAutomaticScreenBrightnessBasedOnLastUsedLux(
+                                    mTempBrightnessEvent);
+                } else {
+                    rawBrightnessState = getDozeBrightnessForOffload();
+                    mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
+                            | BrightnessEvent.FLAG_DOZE_SCALE);
+                }
+
+                if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
+                    brightnessState = clampScreenBrightness(rawBrightnessState);
+                    mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
+
+                    if (mAutomaticBrightnessController != null
+                            && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
+                        // Keep the brightness in the setting so that we can use it after the screen
+                        // turns on, until a lux sample becomes available. We don't do this when
+                        // auto-brightness is disabled - in that situation we still want to use
+                        // the last brightness from when the screen was on.
+                        updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
+                    }
                 }
             }
-        }
 
-        // Use default brightness when dozing unless overridden.
-        if (Float.isNaN(brightnessState) && Display.isDozeState(state)) {
-            rawBrightnessState = mScreenBrightnessDozeConfig;
-            brightnessState = clampScreenBrightness(rawBrightnessState);
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
+            // Use default brightness when dozing unless overridden.
+            if (Float.isNaN(brightnessState)
+                    || displayBrightnessState.getDisplayBrightnessStrategyName()
+                    .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME)) {
+                rawBrightnessState = mScreenBrightnessDozeConfig;
+                brightnessState = clampScreenBrightness(rawBrightnessState);
+                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
+            }
         }
 
         if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
@@ -1502,7 +1511,7 @@
         }
 
         // Apply manual brightness.
-        if (Float.isNaN(brightnessState)) {
+        if (Float.isNaN(brightnessState) && !mFlags.isRefactorDisplayPowerControllerEnabled()) {
             rawBrightnessState = currentBrightnessSetting;
             brightnessState = clampScreenBrightness(rawBrightnessState);
             if (brightnessState != currentBrightnessSetting) {
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 22a21a6..feec4e6 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -32,6 +32,7 @@
 import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy;
 import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
 import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
 import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
@@ -85,6 +86,9 @@
     @Nullable
     private final AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy;
 
+    @Nullable
+    private final FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+
     // A collective representation of all the strategies that the selector is aware of. This is
     // non null, but the strategies this is tracking can be null
     @NonNull
@@ -118,7 +122,8 @@
         mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
         mAutomaticBrightnessStrategy1 =
                 (!mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
-                        : injector.getAutomaticBrightnessStrategy1(context, displayId);
+                        : injector.getAutomaticBrightnessStrategy1(context, displayId,
+                                mDisplayManagerFlags);
         mAutomaticBrightnessStrategy2 =
                 (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
                         : injector.getAutomaticBrightnessStrategy2(context, displayId);
@@ -134,11 +139,14 @@
         } else {
             mOffloadBrightnessStrategy = null;
         }
+        mFallbackBrightnessStrategy = (mDisplayManagerFlags
+                .isRefactorDisplayPowerControllerEnabled())
+                ? injector.getFallbackBrightnessStrategy() : null;
         mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy,
                 mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy,
                 mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy,
                 mAutomaticBrightnessStrategy1, mOffloadBrightnessStrategy,
-                mAutoBrightnessFallbackStrategy};
+                mAutoBrightnessFallbackStrategy, mFallbackBrightnessStrategy};
         mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
                 R.bool.config_allowAutoBrightnessWhileDozing);
         mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
@@ -179,6 +187,12 @@
             displayBrightnessStrategy = mOffloadBrightnessStrategy;
         } else if (isAutoBrightnessFallbackStrategyValid()) {
             displayBrightnessStrategy = mAutoBrightnessFallbackStrategy;
+        } else {
+            // This will become the ultimate fallback strategy once the flag has been fully rolled
+            // out
+            if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
+                displayBrightnessStrategy = mFallbackBrightnessStrategy;
+            }
         }
 
         if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
@@ -330,8 +344,8 @@
         }
 
         AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
-                int displayId) {
-            return new AutomaticBrightnessStrategy(context, displayId);
+                int displayId, DisplayManagerFlags displayManagerFlags) {
+            return new AutomaticBrightnessStrategy(context, displayId, displayManagerFlags);
         }
 
         AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context,
@@ -347,5 +361,9 @@
         AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
             return new AutoBrightnessFallbackStrategy(/* injector= */ null);
         }
+
+        FallbackBrightnessStrategy getFallbackBrightnessStrategy() {
+            return new FallbackBrightnessStrategy();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 2305228..f809a49 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -17,6 +17,9 @@
 
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.BrightnessConfiguration;
@@ -33,6 +36,7 @@
 import com.android.server.display.brightness.BrightnessUtils;
 import com.android.server.display.brightness.StrategyExecutionRequest;
 import com.android.server.display.brightness.StrategySelectionNotifyRequest;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import java.io.PrintWriter;
 
@@ -98,19 +102,24 @@
 
     private Injector mInjector;
 
+    private DisplayManagerFlags mDisplayManagerFlags;
+
     @VisibleForTesting
-    AutomaticBrightnessStrategy(Context context, int displayId, Injector injector) {
+    AutomaticBrightnessStrategy(Context context, int displayId, Injector injector,
+            DisplayManagerFlags displayManagerFlags) {
         super(context, displayId);
         mContext = context;
         mDisplayId = displayId;
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mDisplayManagerFlags  = displayManagerFlags;
         mInjector = (injector == null) ? new RealInjector() : injector;
     }
 
-    public AutomaticBrightnessStrategy(Context context, int displayId) {
-        this(context, displayId, null);
+    public AutomaticBrightnessStrategy(Context context, int displayId,
+            DisplayManagerFlags displayManagerFlags) {
+        this(context, displayId, null, displayManagerFlags);
     }
 
     /**
@@ -120,6 +129,7 @@
     public void setAutoBrightnessState(int targetDisplayState,
             boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
             float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
+        switchMode(targetDisplayState);
         final boolean autoBrightnessEnabledInDoze =
                 allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
         mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
@@ -479,6 +489,16 @@
         }
     }
 
+
+    private void switchMode(int state) {
+        if (mDisplayManagerFlags.areAutoBrightnessModesEnabled()
+                && mAutomaticBrightnessController != null
+                && !mAutomaticBrightnessController.isInIdleMode()) {
+            mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
+                    ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+        }
+    }
+
     /**
      * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet.
      * Temporary brightness adjustments happen when the user moves the brightness slider in the
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
index 504683a..7b2f2b9 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java
@@ -18,4 +18,5 @@
 
 public class DisplayBrightnessStrategyConstants {
     static final String INVALID_BRIGHTNESS_STRATEGY_NAME = "InvalidBrightnessStrategy";
+    public static final String FALLBACK_BRIGHTNESS_STRATEGY_NAME = "FallbackBrightnessStrategy";
 }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
new file mode 100644
index 0000000..3463649a
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java
@@ -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.server.display.brightness.strategy;
+
+import android.annotation.NonNull;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.StrategyExecutionRequest;
+import com.android.server.display.brightness.StrategySelectionNotifyRequest;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the brightness of the associated display when no other strategy qualifies for
+ * setting up the brightness state. This strategy is also being used for evaluating the
+ * display brightness state when we have a manually set brightness. This is a temporary state, and
+ * the logic for evaluating the manual brightness will be moved to a separate strategy
+ */
+public class FallbackBrightnessStrategy implements DisplayBrightnessStrategy{
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            StrategyExecutionRequest strategyExecutionRequest) {
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
+        return new DisplayBrightnessState.Builder()
+                .setBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
+                .setSdrBrightness(strategyExecutionRequest.getCurrentScreenBrightness())
+                .setBrightnessReason(brightnessReason)
+                .setDisplayBrightnessStrategyName(getName())
+                // The fallback brightness might change due to clamping. Make sure we tell the rest
+                // of the system by updating the setting
+                .setShouldUpdateScreenBrightnessSetting(true)
+                .build();
+    }
+
+    @NonNull
+    @Override
+    public String getName() {
+        return DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME;
+    }
+
+    @Override
+    public int getReason() {
+        return BrightnessReason.REASON_MANUAL;
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+
+    }
+
+    @Override
+    public void strategySelectionPostProcessor(
+            StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
+
+    }
+}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 816242d..c6aef7f 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -249,14 +249,14 @@
         mCurrentDream.mAppTask = appTask;
     }
 
-    void setDreamHasFocus(boolean hasFocus) {
+    void setDreamIsObscured(boolean isObscured) {
         if (mCurrentDream != null) {
-            mCurrentDream.mDreamHasFocus = hasFocus;
+            mCurrentDream.mDreamIsObscured = isObscured;
         }
     }
 
-    boolean dreamHasFocus() {
-        return mCurrentDream != null && mCurrentDream.mDreamHasFocus;
+    boolean dreamIsFrontmost() {
+        return mCurrentDream != null && mCurrentDream.dreamIsFrontmost();
     }
 
     /**
@@ -451,7 +451,7 @@
         private String mStopReason;
         private long mDreamStartTime;
         public boolean mWakingGently;
-        public boolean mDreamHasFocus;
+        private boolean mDreamIsObscured;
 
         private final Runnable mStopPreviousDreamsIfNeeded = this::stopPreviousDreamsIfNeeded;
         private final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded;
@@ -549,5 +549,9 @@
                 mHandler.removeCallbacks(mReleaseWakeLockIfNeeded);
             }
         }
+
+        boolean dreamIsFrontmost() {
+            return !mDreamIsObscured;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 2def5ae..18a9986 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -20,7 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.service.dreams.Flags.dreamTracksFocus;
+import static android.service.dreams.Flags.dreamHandlesBeingObscured;
 
 import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID;
 
@@ -428,7 +428,7 @@
             // Can't start dreaming if we are already dreaming and the dream has focus. If we are
             // dreaming but the dream does not have focus, then the dream can be brought to the
             // front so it does have focus.
-            if (isScreenOn && isDreamingInternal() && dreamHasFocus()) {
+            if (isScreenOn && isDreamingInternal() && dreamIsFrontmost()) {
                 return false;
             }
 
@@ -463,9 +463,10 @@
         }
     }
 
-    private boolean dreamHasFocus() {
-        // Dreams always had focus before they were able to track it.
-        return !dreamTracksFocus() || mController.dreamHasFocus();
+    private boolean dreamIsFrontmost() {
+        // Dreams were always considered frontmost before they began tracking whether they are
+        // obscured.
+        return !dreamHandlesBeingObscured() || mController.dreamIsFrontmost();
     }
 
     protected void requestStartDreamFromShell() {
@@ -473,7 +474,7 @@
     }
 
     private void requestDreamInternal() {
-        if (isDreamingInternal() && !dreamHasFocus() && mController.bringDreamToFront()) {
+        if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) {
             return;
         }
 
@@ -1159,10 +1160,16 @@
         }
 
         @Override
-        public void onDreamFocusChanged(boolean hasFocus) {
+        public void setDreamIsObscured(boolean isObscured) {
+            if (!dreamHandlesBeingObscured()) {
+                return;
+            }
+
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
             final long ident = Binder.clearCallingIdentity();
             try {
-                mController.setDreamHasFocus(hasFocus);
+                mHandler.post(() -> mController.setDreamIsObscured(isObscured));
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java
index b47631c3..d32a5ed 100644
--- a/services/core/java/com/android/server/input/InputManagerInternal.java
+++ b/services/core/java/com/android/server/input/InputManagerInternal.java
@@ -218,4 +218,13 @@
      * display, external peripherals, fingerprint sensor, etc.
      */
     public abstract void notifyUserActivity();
+
+    /**
+     * Get the device ID of the {@link InputDevice} that used most recently.
+     *
+     * @return the last used input device ID, or
+     *     {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used
+     *     since boot.
+     */
+    public abstract int getLastUsedInputDeviceId();
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8317991..8685d2c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3204,6 +3204,11 @@
         public void setStylusButtonMotionEventsEnabled(boolean enabled) {
             mNative.setStylusButtonMotionEventsEnabled(enabled);
         }
+
+        @Override
+        public int getLastUsedInputDeviceId() {
+            return mNative.getLastUsedInputDeviceId();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index f742360..0208a32 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -271,6 +271,15 @@
 
     void setInputMethodConnectionIsActive(boolean isActive);
 
+    /**
+     * Get the device ID of the InputDevice that used most recently.
+     *
+     * @return the last used input device ID, or
+     *     {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used
+     *     since boot.
+     */
+    int getLastUsedInputDeviceId();
+
     /** The native implementation of InputManagerService methods. */
     class NativeImpl implements NativeInputManagerService {
         /** Pointer to native input manager service object, used by native code. */
@@ -544,5 +553,8 @@
 
         @Override
         public native void setInputMethodConnectionIsActive(boolean isActive);
+
+        @Override
+        public native int getLastUsedInputDeviceId();
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 67df992..691145c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -533,21 +533,6 @@
     EditorInfo mCurEditorInfo;
 
     /**
-     * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
-     * connected to or in the process of connecting to.
-     *
-     * <p>This can be {@code null} when no input method is connected.</p>
-     *
-     * @see #getSelectedMethodIdLocked()
-     */
-    @GuardedBy("ImfLock.class")
-    @Nullable
-    private String getCurIdLocked() {
-        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
-        return userData.mBindingController.getCurId();
-    }
-
-    /**
      * The current subtype of the current input method.
      */
     @MultiUserUnawareField
@@ -577,16 +562,6 @@
     boolean mInFullscreenMode;
 
     /**
-     * The Intent used to connect to the current input method.
-     */
-    @GuardedBy("ImfLock.class")
-    @Nullable
-    private Intent getCurIntentLocked() {
-        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
-        return userData.mBindingController.getCurIntent();
-    }
-
-    /**
      * The token we have made for the currently active input method, to
      * identify it in the future.
      */
@@ -632,15 +607,6 @@
     }
 
     /**
-     * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}.
-     */
-    @GuardedBy("ImfLock.class")
-    private int getCurMethodUidLocked() {
-        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
-        return userData.mBindingController.getCurMethodUid();
-    }
-
-    /**
      * Have we called mCurMethod.bindInput()?
      */
     @MultiUserUnawareField
@@ -2011,8 +1977,8 @@
         final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
         final StartInputInfo info = new StartInputInfo(mCurrentUserId,
                 getCurTokenLocked(),
-                mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting,
-                UserHandle.getUserId(mCurClient.mUid),
+                mCurTokenDisplayId, userData.mBindingController.getCurId(), startInputReason,
+                restarting, UserHandle.getUserId(mCurClient.mUid),
                 mCurClient.mSelfReportedDisplayId, mImeBindingState.mFocusedWindow, mCurEditorInfo,
                 mImeBindingState.mFocusedWindowSoftInputMode,
                 userData.mBindingController.getSequenceNumber());
@@ -2026,8 +1992,8 @@
         // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
         if (mCurrentUserId == UserHandle.getUserId(
                 mCurClient.mUid)) {
-            mPackageManagerInternal.grantImplicitAccess(mCurrentUserId,
-                    null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()),
+            mPackageManagerInternal.grantImplicitAccess(mCurrentUserId, null /* intent */,
+                    UserHandle.getAppId(userData.mBindingController.getCurMethodUid()),
                     mCurClient.mUid, true /* direct */);
         }
 
@@ -2048,7 +2014,7 @@
                     null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
         }
 
-        final var curId = getCurIdLocked();
+        final var curId = userData.mBindingController.getCurId();
         final InputMethodInfo curInputMethodInfo = InputMethodSettingsRepository.get(mCurrentUserId)
                 .getMethodMap().get(curId);
         final boolean suppressesSpellChecker =
@@ -2337,7 +2303,8 @@
                 requestClientSessionForAccessibilityLocked(cs);
                 return new InputBindResult(
                         InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
-                        null, null, null, getCurIdLocked(),
+                        null, null, null,
+                        userData.mBindingController.getCurId(),
                         userData.mBindingController.getSequenceNumber(), false);
             } else {
                 final long lastBindTime = userData.mBindingController.getLastBindTime();
@@ -2352,7 +2319,8 @@
                     // to see if we can get back in touch with the service.
                     return new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
-                            null, null, null, getCurIdLocked(),
+                            null, null, null,
+                            userData.mBindingController.getCurId(),
                             userData.mBindingController.getSequenceNumber(), false);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
@@ -2707,7 +2675,8 @@
         // When the IME switcher dialog is shown, the IME switcher button should be hidden.
         if (mMenuController.getSwitchingDialogLocked() != null) return false;
         // When we are switching IMEs, the IME switcher button should be hidden.
-        if (!Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+        if (!Objects.equals(userData.mBindingController.getCurId(), getSelectedMethodIdLocked())) {
             return false;
         }
         if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
@@ -2869,8 +2838,10 @@
             } else {
                 vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
             }
+            final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+            final var curId = userData.mBindingController.getCurId();
             if (mMenuController.getSwitchingDialogLocked() != null
-                    || !Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) {
+                    || !Objects.equals(curId, getSelectedMethodIdLocked())) {
                 // When the IME switcher dialog is shown, or we are switching IMEs,
                 // the back button should be in the default state (as if the IME is not shown).
                 backDisposition = InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING;
@@ -3831,10 +3802,10 @@
         if (mCurrentUserId != UserHandle.getUserId(uid)) {
             return false;
         }
-        if (getCurIntentLocked() != null && InputMethodUtils.checkIfPackageBelongsToUid(
-                mPackageManagerInternal,
-                uid,
-                getCurIntentLocked().getComponent().getPackageName())) {
+        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+        final var curIntent = userData.mBindingController.getCurIntent();
+        if (curIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
+                mPackageManagerInternal, uid, curIntent.getComponent().getPackageName())) {
             return true;
         }
         return false;
@@ -4438,7 +4409,7 @@
             if (mCurEditorInfo != null) {
                 mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE);
             }
-            proto.write(CUR_ID, getCurIdLocked());
+            proto.write(CUR_ID, userData.mBindingController.getCurId());
             mVisibilityStateComputer.dumpDebug(proto, fieldId);
             proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
             proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
@@ -4895,7 +4866,10 @@
             if (mCurClient == null || mCurClient.mClient == null) {
                 return;
             }
-            if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) {
+            // TODO(b/325515685): user data must be retrieved by a userId parameter
+            final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+            if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(
+                    userData.mBindingController.getCurMethodUid())) {
                 // Handle IME visibility when interactive changed before finishing the input to
                 // ensure we preserve the last state as possible.
                 final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
@@ -5648,7 +5622,7 @@
                     final InputBindResult res = new InputBindResult(
                             InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
                             imeSession, accessibilityInputMethodSessions, /* channel= */ null,
-                            getCurIdLocked(),
+                            userData.mBindingController.getCurId(),
                             userData.mBindingController.getSequenceNumber(),
                             /* isInputMethodSuppressingSpellChecker= */ false);
                     mCurClient.mClient.onBindAccessibilityService(res, accessibilityConnectionId);
@@ -5901,7 +5875,7 @@
             p.println("  mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
             mImeBindingState.dump(/* prefix= */ "  ", p);
 
-            p.println("  mCurId=" + getCurIdLocked()
+            p.println("  mCurId=" + userData.mBindingController.getCurId()
                     + " mHaveConnection=" + userData.mBindingController.hasMainConnection()
                     + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
                     + userData.mBindingController.isVisibleBound());
@@ -5920,7 +5894,7 @@
             p.println("  mCurToken=" + getCurTokenLocked());
             p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
             p.println("  mCurHostInputToken=" + mAutofillController.getCurHostInputToken());
-            p.println("  mCurIntent=" + getCurIntentLocked());
+            p.println("  mCurIntent=" + userData.mBindingController.getCurIntent());
             method = getCurMethodLocked();
             p.println("  mCurMethod=" + getCurMethodLocked());
             p.println("  mEnabledSession=" + mEnabledSession);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 964bff0..4ff345f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1066,8 +1066,6 @@
         if (isAutoLockingPrivateSpaceOnRestartsEnabled()) {
             autoLockPrivateSpace();
         }
-
-        markEphemeralUsersForRemoval();
     }
 
     private boolean isAutoLockingPrivateSpaceOnRestartsEnabled() {
@@ -1104,21 +1102,6 @@
         }
     }
 
-    /** Marks all ephemeral users as slated for deletion. **/
-    private void markEphemeralUsersForRemoval() {
-        synchronized (mUsersLock) {
-            final int userSize = mUsers.size();
-            for (int i = 0; i < userSize; i++) {
-                final UserInfo ui = mUsers.valueAt(i).info;
-                if (ui.isEphemeral() && !ui.preCreated && ui.id != UserHandle.USER_SYSTEM) {
-                    addRemovingUserIdLocked(ui.id);
-                    ui.partial = true;
-                    ui.flags |= UserInfo.FLAG_DISABLED;
-                }
-            }
-        }
-    }
-
     /* Prunes out any partially created or partially removed users. */
     private void cleanupPartialUsers() {
         ArrayList<UserInfo> partials = new ArrayList<>();
@@ -4229,6 +4212,13 @@
                                             || mNextSerialNumber <= userData.info.id) {
                                         mNextSerialNumber = userData.info.id + 1;
                                     }
+                                    if (userData.info.isEphemeral() && !userData.info.preCreated
+                                            && userData.info.id != UserHandle.USER_SYSTEM) {
+                                        // Mark ephemeral user as slated for deletion.
+                                        addRemovingUserIdLocked(userData.info.id);
+                                        userData.info.partial = true;
+                                        userData.info.flags |= UserInfo.FLAG_DISABLED;
+                                    }
                                 }
                             }
                         } else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 21e4c96..edf09f1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -11111,7 +11111,7 @@
      * Otherwise, return the creation time of the top window.
      */
     long getLastWindowCreateTime() {
-        final WindowState window = getWindow(win -> true);
+        final WindowState window = getWindow(alwaysTruePredicate());
         return window != null && window.mAttrs.type != TYPE_BASE_APPLICATION
                 ? window.getCreateTime()
                 : createTime;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c9703d8..0e4f033 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1732,7 +1732,10 @@
             // The activity was detached from hierarchy.
             return;
         }
-        activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+
+        if (activity.mDisplayContent.isFixedRotationLaunchingApp(activity)) {
+            activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
+        }
 
         // Restore the launch-behind state.
         activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c9a5e71..a5853c0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2755,7 +2755,7 @@
 
     @Nullable
     Task getTopRootTask() {
-        return getRootTask(t -> true);
+        return getRootTask(alwaysTruePredicate());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 2c27b98..eff8315 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -223,7 +223,7 @@
 
     @VisibleForTesting
     Task getTopRootTask() {
-        return getRootTask(t -> true);
+        return getRootTask(alwaysTruePredicate());
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d70ca02..edbba92 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -116,6 +116,7 @@
 import com.android.server.wm.SurfaceAnimator.Animatable;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.AlwaysTruePredicate;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -2019,29 +2020,34 @@
                 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
     }
 
+    @SuppressWarnings("unchecked")
+    static <T> Predicate<T> alwaysTruePredicate() {
+        return (Predicate<T>) AlwaysTruePredicate.INSTANCE;
+    }
+
     ActivityRecord getActivityAbove(ActivityRecord r) {
-        return getActivity((above) -> true, r,
+        return getActivity(alwaysTruePredicate(), r /* boundary */,
                 false /*includeBoundary*/, false /*traverseTopToBottom*/);
     }
 
     ActivityRecord getActivityBelow(ActivityRecord r) {
-        return getActivity((below) -> true, r,
+        return getActivity(alwaysTruePredicate(), r /* boundary */,
                 false /*includeBoundary*/, true /*traverseTopToBottom*/);
     }
 
     ActivityRecord getBottomMostActivity() {
-        return getActivity((r) -> true, false /*traverseTopToBottom*/);
+        return getActivity(alwaysTruePredicate(), false /* traverseTopToBottom */);
     }
 
     ActivityRecord getTopMostActivity() {
-        return getActivity((r) -> true, true /*traverseTopToBottom*/);
+        return getActivity(alwaysTruePredicate(), true /* traverseTopToBottom */);
     }
 
     ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) {
         // Break down into 4 calls to avoid object creation due to capturing input params.
         if (includeFinishing) {
             if (includeOverlays) {
-                return getActivity((r) -> true);
+                return getActivity(alwaysTruePredicate());
             }
             return getActivity((r) -> !r.isTaskOverlay());
         } else if (includeOverlays) {
@@ -2220,21 +2226,17 @@
         }
     }
 
-    Task getTaskAbove(Task t) {
-        return getTask(
-                (above) -> true, t, false /*includeBoundary*/, false /*traverseTopToBottom*/);
-    }
-
     Task getTaskBelow(Task t) {
-        return getTask((below) -> true, t, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+        return getTask(alwaysTruePredicate(), t /* boundary */,
+                false /* includeBoundary */, true /* traverseTopToBottom */);
     }
 
     Task getBottomMostTask() {
-        return getTask((t) -> true, false /*traverseTopToBottom*/);
+        return getTask(alwaysTruePredicate(), false /* traverseTopToBottom */);
     }
 
     Task getTopMostTask() {
-        return getTask((t) -> true, true /*traverseTopToBottom*/);
+        return getTask(alwaysTruePredicate(), true /* traverseTopToBottom */);
     }
 
     Task getTask(Predicate<Task> callback) {
diff --git a/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java b/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java
new file mode 100644
index 0000000..49dcb6c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/AlwaysTruePredicate.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import java.util.function.Predicate;
+
+/** A simple Predicate to avoid synthetic allocation of lambda expression "o -> true". */
+public class AlwaysTruePredicate implements Predicate<Object> {
+
+    public static final AlwaysTruePredicate INSTANCE = new AlwaysTruePredicate();
+
+    private AlwaysTruePredicate() {
+    }
+
+    @Override
+    public boolean test(Object o) {
+        return true;
+    }
+}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index a01c123..74ca9ad 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -423,7 +423,7 @@
         std::set<int32_t> disabledInputDevices{};
 
         // Associated Pointer controller display.
-        ui::LogicalDisplayId pointerDisplayId{ui::ADISPLAY_ID_DEFAULT};
+        ui::LogicalDisplayId pointerDisplayId{ui::LogicalDisplayId::DEFAULT};
 
         // True if stylus button reporting through motion events is enabled.
         bool stylusButtonMotionEventsEnabled{true};
@@ -1886,7 +1886,7 @@
                                         jstring nameObj, jint pid) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
 
-    if (displayId == ui::ADISPLAY_ID_NONE.val()) {
+    if (ui::LogicalDisplayId{displayId} == ui::LogicalDisplayId::INVALID) {
         std::string message = "InputChannel used as a monitor must be associated with a display";
         jniThrowRuntimeException(env, message.c_str());
         return nullptr;
@@ -2727,6 +2727,11 @@
     im->setInputMethodConnectionIsActive(isActive);
 }
 
+static jint nativeGetLastUsedInputDeviceId(JNIEnv* env, jobject nativeImplObj) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    return static_cast<jint>(im->getInputManager()->getReader().getLastUsedInputDeviceId());
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -2835,6 +2840,7 @@
         {"setAccessibilityStickyKeysEnabled", "(Z)V",
          (void*)nativeSetAccessibilityStickyKeysEnabled},
         {"setInputMethodConnectionIsActive", "(Z)V", (void*)nativeSetInputMethodConnectionIsActive},
+        {"getLastUsedInputDeviceId", "()I", (void*)nativeGetLastUsedInputDeviceId},
 };
 
 #define FIND_CLASS(var, className) \
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 ae6361b..df96712 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
@@ -46,6 +46,7 @@
 import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy;
 import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
 import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
 import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
@@ -90,6 +91,8 @@
     @Mock
     private AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy;
     @Mock
+    private FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+    @Mock
     private Resources mResources;
     @Mock
     private DisplayManagerFlags mDisplayManagerFlags;
@@ -135,7 +138,7 @@
 
                 @Override
                 AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
-                        int displayId) {
+                        int displayId, DisplayManagerFlags displayManagerFlags) {
                     return mAutomaticBrightnessStrategy;
                 }
 
@@ -155,6 +158,11 @@
                 AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
                     return mAutoBrightnessFallbackStrategy;
                 }
+
+                @Override
+                FallbackBrightnessStrategy getFallbackBrightnessStrategy() {
+                    return mFallbackBrightnessStrategy;
+                }
             };
 
     @Rule
@@ -355,6 +363,25 @@
     }
 
     @Test
+    public void selectStrategy_selectsFallbackStrategyAsAnUltimateFallback() {
+        when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+        mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+                mInjector, DISPLAY_ID, mDisplayManagerFlags);
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN);
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
+        when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(false);
+        when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(false);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(
+                        new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON,
+                                0.1f, false)),
+                mFallbackBrightnessStrategy);
+    }
+
+    @Test
     public void selectStrategyCallsPostProcessorForAllStrategies() {
         when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
         mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 3e78118..19bff56 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -18,8 +18,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.any;
 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;
@@ -45,6 +47,7 @@
 import com.android.server.display.brightness.BrightnessEvent;
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.brightness.StrategyExecutionRequest;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -64,6 +67,9 @@
     @Mock
     private AutomaticBrightnessController mAutomaticBrightnessController;
 
+    @Mock
+    private DisplayManagerFlags mDisplayManagerFlags;
+
     private BrightnessConfiguration mBrightnessConfiguration;
     private float mDefaultScreenAutoBrightnessAdjustment;
     private Context mContext;
@@ -80,7 +86,8 @@
                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, Float.NaN);
         Settings.System.putFloat(mContext.getContentResolver(),
                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.5f);
-        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID,
+                mDisplayManagerFlags);
 
         mBrightnessConfiguration = new BrightnessConfiguration.Builder(
                 new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build();
@@ -247,6 +254,46 @@
     }
 
     @Test
+    public void testAutoBrightnessState_modeSwitch() {
+        // Setup the test
+        when(mDisplayManagerFlags.areAutoBrightnessModesEnabled()).thenReturn(true);
+        mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
+        boolean allowAutoBrightnessWhileDozing = false;
+        int brightnessReason = BrightnessReason.REASON_UNKNOWN;
+        float lastUserSetBrightness = 0.2f;
+        boolean userSetBrightnessChanged = true;
+        int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+        float pendingBrightnessAdjustment = 0.1f;
+        Settings.System.putFloat(mContext.getContentResolver(),
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment);
+        mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments();
+
+        // Validate no interaction when automaticBrightnessController is in idle mode
+        when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(true);
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController, never()).switchMode(anyInt());
+
+        // Validate interaction when automaticBrightnessController is in non-idle mode, and display
+        // state is ON
+        when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(false);
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController).switchMode(
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT);
+
+        // Validate interaction when automaticBrightnessController is in non-idle mode, and display
+        // state is DOZE
+        mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_DOZE,
+                allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
+                userSetBrightnessChanged);
+        verify(mAutomaticBrightnessController).switchMode(
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE);
+    }
+
+    @Test
     public void accommodateUserBrightnessChangesWorksAsExpected() {
         // Verify the state if automaticBrightnessController is configured.
         assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive());
@@ -390,7 +437,8 @@
     @Test
     public void testVerifyNoAutoBrightnessAdjustmentsArePopulatedForNonDefaultDisplay() {
         int newDisplayId = 1;
-        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId);
+        mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId,
+                mDisplayManagerFlags);
         mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(0.3f);
         assertEquals(0.5f, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(),
                 0.0f);
@@ -429,8 +477,7 @@
             updateBrightness_constructsDisplayBrightnessState_withAdjustmentAutoAdjustmentFlag() {
         BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
         mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
-                mContext, DISPLAY_ID, displayId -> brightnessEvent);
-        new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+                mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 mAutomaticBrightnessController);
         float brightness = 0.4f;
@@ -461,8 +508,7 @@
             updateBrightness_constructsDisplayBrightnessState_withAdjustmentTempAdjustmentFlag() {
         BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID);
         mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(
-                mContext, DISPLAY_ID, displayId -> brightnessEvent);
-        new AutomaticBrightnessStrategy(mContext, DISPLAY_ID);
+                mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 mAutomaticBrightnessController);
         float brightness = 0.4f;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
new file mode 100644
index 0000000..c4767ae
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.display.brightness.strategy;
+
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.StrategyExecutionRequest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+
+public class FallbackBrightnessStrategyTest {
+    private FallbackBrightnessStrategy mFallbackBrightnessStrategy;
+
+    @Before
+    public void before() {
+        mFallbackBrightnessStrategy = new FallbackBrightnessStrategy();
+    }
+
+    @Test
+    public void updateBrightness_currentBrightnessIsSet() {
+        DisplayManagerInternal.DisplayPowerRequest
+                displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+        float currentBrightness = 0.2f;
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_MANUAL);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(currentBrightness)
+                        .setBrightnessReason(brightnessReason)
+                        .setSdrBrightness(currentBrightness)
+                        .setDisplayBrightnessStrategyName(mFallbackBrightnessStrategy.getName())
+                        .setShouldUpdateScreenBrightnessSetting(true)
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mFallbackBrightnessStrategy.updateBrightness(
+                        new StrategyExecutionRequest(displayPowerRequest, currentBrightness));
+        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+    }
+}
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
index 88ab871..874e991 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java
@@ -273,28 +273,36 @@
     }
 
     @Test
-    public void setDreamHasFocus_true_dreamHasFocus() {
+    public void setDreamIsObscured_true_dreamIsNotFrontmost() {
         mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
                 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
 
-        mDreamController.setDreamHasFocus(true);
-        assertTrue(mDreamController.dreamHasFocus());
+        mDreamController.setDreamIsObscured(true);
+        assertFalse(mDreamController.dreamIsFrontmost());
     }
 
     @Test
-    public void setDreamHasFocus_false_dreamDoesNotHaveFocus() {
+    public void setDreamIsObscured_false_dreamIsFrontmost() {
         mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
                 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
 
-        mDreamController.setDreamHasFocus(false);
-        assertFalse(mDreamController.dreamHasFocus());
+        mDreamController.setDreamIsObscured(false);
+        assertTrue(mDreamController.dreamIsFrontmost());
     }
 
     @Test
-    public void setDreamHasFocus_notDreaming_dreamDoesNotHaveFocus() {
-        mDreamController.setDreamHasFocus(true);
-        // Dream still doesn't have focus because it was never started.
-        assertFalse(mDreamController.dreamHasFocus());
+    public void setDreamIsObscured_notDreaming_dreamIsNotFrontmost() {
+        mDreamController.setDreamIsObscured(true);
+        // Dream still isn't frontmost because it was never started.
+        assertFalse(mDreamController.dreamIsFrontmost());
+    }
+
+    @Test
+    public void startDream_dreamIsFrontmost() {
+        mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+                0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+
+        assertTrue(mDreamController.dreamIsFrontmost());
     }
 
     private ServiceConnection captureServiceConnection() {
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index da8368f..2b6ddcb 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -32,6 +32,9 @@
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
+/**
+ * To run this test: `atest FlickerTestsIme1:CloseImeOnDismissPopupDialogTest`
+ */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 2f3ec63..0344197 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -33,8 +33,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window closing to home transitions. To run this test: `atest
- * FlickerTests:CloseImeWindowToHomeTest`
+ * Test IME window closing to home transitions.
+ * To run this test: `atest FlickerTestsIme1:CloseImeOnGoHomeTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index 8821b69..fde1373 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -42,7 +42,7 @@
  *
  * More details on b/190352379
  *
- * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartOnGoHomeTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index d75eba6..dc50135 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -42,7 +42,7 @@
  *
  * More details on b/190352379
  *
- * To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeShownOnAppStartToAppOnPressBackTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 41d9e30..dc2bd1b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -34,8 +34,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window closing back to app window transitions. To run this test: `atest
- * FlickerTests:CloseImeWindowToAppTest`
+ * Test IME window closing back to app window transitions.
+ * To run this test: `atest FlickerTestsIme1:CloseImeToAppOnPressBackTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index 0e7fb79..05771e8 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -40,7 +40,7 @@
  * Unlike {@link OpenImeWindowTest} testing IME window opening transitions, this test also verify
  * there is no flickering when back to the simple activity without requesting IME to show.
  *
- * To run this test: `atest FlickerTests:OpenImeWindowAndCloseTest`
+ * To run this test: `atest FlickerTestsIme1:CloseImeToHomeOnFinishActivityTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 47a7e1b..336fe6f 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -36,8 +36,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window shown on the app with fixing portrait orientation. To run this test: `atest
- * FlickerTests:OpenImeWindowToFixedPortraitAppTest`
+ * Test IME window shown on the app with fixing portrait orientation.
+ * To run this test: `atest FlickerTestsIme2:OpenImeWindowToFixedPortraitAppTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index 48ec4d1..b8f11dc 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -38,8 +38,9 @@
 
 /**
  * Test IME window layer will become visible when switching from the fixed orientation activity
- * (e.g. Launcher activity). To run this test: `atest
- * FlickerTests:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
+ * (e.g. Launcher activity).
+ * To run this test:
+ * `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index 03f3a68..34a7085 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -33,7 +33,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window opening transitions. To run this test: `atest FlickerTests:ReOpenImeWindowTest`
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromOverviewTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 7b62c89..7c72c31 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -35,8 +35,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME windows switching with 2-Buttons or gestural navigation. To run this test: `atest
- * FlickerTests:SwitchImeWindowsFromGestureNavTest`
+ * Test IME windows switching with 2-Buttons or gestural navigation.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 53bfb4e..fe5320c 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -36,7 +36,7 @@
 /**
  * Launch an app that automatically displays the IME
  *
- * To run this test: `atest FlickerTests:LaunchAppShowImeOnStartTest`
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnAppStartWhenLaunchingAppTest`
  *
  * Actions:
  * ```
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
index d22bdcf..92b6b93 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
@@ -35,8 +35,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window closing on lock and opening on screen unlock. To run this test: `atest
- * FlickerTests:CloseImeWindowToHomeTest`
+ * Test IME window closing on lock and opening on screen unlock.
+ * To run this test: `atest FlickerTestsIme2:ShowImeOnUnlockScreenTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 12290af..9eaf998 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -31,7 +31,10 @@
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
-/** Test IME window opening transitions. To run this test: `atest FlickerTests:OpenImeWindowTest` */
+/**
+ * Test IME window opening transitions.
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhenFocusingOnInputFieldTest`
+ */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 0948351..7186a2c 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -41,7 +41,7 @@
 
 /**
  * Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
- * To run this test: `atest FlickerTests:LaunchAppShowImeAndDialogThemeAppTest`
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhileDismissingThemedPopupDialogTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index 7aa525f..c96c760 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -37,8 +37,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test IME window layer will be associated with the app task when going to the overview screen. To
- * run this test: `atest FlickerTests:OpenImeWindowToOverViewTest`
+ * Test IME window layer will be associated with the app task when going to the overview screen.
+ * To run this test: `atest FlickerTestsIme2:ShowImeWhileEnteringOverviewTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
index ffaeead..8c9ab9a 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
@@ -40,7 +40,7 @@
  *
  * This test assumes the device doesn't have AOD enabled
  *
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationCold`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationColdTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
index 6e67e19..e595100a 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -40,7 +40,7 @@
  *
  * This test assumes the device doesn't have AOD enabled
  *
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationWarm`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationWarmTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index f1df8a6..fbe1d34 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -40,7 +40,8 @@
  *
  * This test assumes the device doesn't have AOD enabled
  *
- * To run this test: `atest FlickerTests:OpenAppFromLockNotificationWithLockOverlayApp`
+ * To run this test:
+ * `atest FlickerTestsNotification:OpenAppFromLockscreenNotificationWithOverlayAppTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
index b6d09d0..c8ca644 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
@@ -36,7 +36,7 @@
 /**
  * Test cold launching an app from a notification.
  *
- * To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromNotificationColdTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 1e607bf..c29e71c 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -47,7 +47,7 @@
 /**
  * Test cold launching an app from a notification.
  *
- * To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
+ * To run this test: `atest FlickerTestsNotification:OpenAppFromNotificationWarmTest`
  */
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 16785d1..6b360b7 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -25,6 +25,7 @@
         val aidlPolicy: FilterPolicyWithReason?,
         val featureFlagsPolicy: FilterPolicyWithReason?,
         val syspropsPolicy: FilterPolicyWithReason?,
+        val rFilePolicy: FilterPolicyWithReason?,
         fallback: OutputFilter
 ) : DelegatingFilter(fallback) {
     override fun getPolicyForClass(className: String): FilterPolicyWithReason {
@@ -37,6 +38,9 @@
         if (syspropsPolicy != null && classes.isSyspropsClass(className)) {
             return syspropsPolicy
         }
+        if (rFilePolicy != null && classes.isRClass(className)) {
+            return rFilePolicy
+        }
         return super.getPolicyForClass(className)
     }
 }
@@ -74,3 +78,10 @@
     return className.startsWith("android/sysprop/")
             && className.endsWith("Properties")
 }
+
+/**
+ * @return if a given class "seems like" an R class or its nested classes.
+ */
+private fun ClassNodes.isRClass(className: String): Boolean {
+    return className.endsWith("/R") || className.contains("/R$")
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 75b5fc8..c5acd81 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -17,6 +17,7 @@
 
 import com.android.hoststubgen.ParseException
 import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.toHumanReadableClassName
 import com.android.hoststubgen.log
 import com.android.hoststubgen.normalizeTextLine
 import com.android.hoststubgen.whitespaceRegex
@@ -31,13 +32,17 @@
  * Print a class node as a "keep" policy.
  */
 fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) {
-    pw.printf("class %s\t%s\n", cn.name, "keep")
+    pw.printf("class %s %s\n", cn.name.toHumanReadableClassName(), "keep")
 
-    for (f in cn.fields ?: emptyList()) {
-        pw.printf("  field %s\t%s\n", f.name, "keep")
+    cn.fields?.let {
+        for (f in it.sortedWith(compareBy({ it.name }))) {
+            pw.printf("    field %s %s\n", f.name, "keep")
+        }
     }
-    for (m in cn.methods ?: emptyList()) {
-        pw.printf("  method %s\t%s\t%s\n", m.name, m.desc, "keep")
+    cn.methods?.let {
+        for (m in it.sortedWith(compareBy({ it.name }, { it.desc }))) {
+            pw.printf("    method %s %s %s\n", m.name, m.desc, "keep")
+        }
     }
 }
 
@@ -66,6 +71,7 @@
         var aidlPolicy: FilterPolicyWithReason? = null
         var featureFlagsPolicy: FilterPolicyWithReason? = null
         var syspropsPolicy: FilterPolicyWithReason? = null
+        var rFilePolicy: FilterPolicyWithReason? = null
 
         try {
             BufferedReader(FileReader(filename)).use { reader ->
@@ -162,6 +168,14 @@
                                         syspropsPolicy = policy.withReason(
                                                 "$FILTER_REASON (special-class sysprops)")
                                     }
+                                    SpecialClass.RFile -> {
+                                        if (rFilePolicy != null) {
+                                            throw ParseException(
+                                                "Policy for R file already defined")
+                                        }
+                                        rFilePolicy = policy.withReason(
+                                            "$FILTER_REASON (special-class R file)")
+                                    }
                                 }
                             }
                         }
@@ -225,13 +239,9 @@
             throw e.withSourceInfo(filename, lineNo)
         }
 
-        var ret: OutputFilter = imf
-        if (aidlPolicy != null || featureFlagsPolicy != null || syspropsPolicy != null) {
-            log.d("AndroidHeuristicsFilter enabled")
-            ret = AndroidHeuristicsFilter(
-                    classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, imf)
-        }
-        return ret
+        // Wrap the in-memory-filter with AHF.
+        return AndroidHeuristicsFilter(
+                classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf)
     }
 }
 
@@ -240,6 +250,7 @@
     Aidl,
     FeatureFlags,
     Sysprops,
+    RFile,
 }
 
 private fun resolveSpecialClass(className: String): SpecialClass {
@@ -250,6 +261,7 @@
         ":aidl" -> return SpecialClass.Aidl
         ":feature_flags" -> return SpecialClass.FeatureFlags
         ":sysprops" -> return SpecialClass.Sysprops
+        ":r" -> return SpecialClass.RFile
     }
     throw ParseException("Invalid special class name \"$className\"")
 }
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index fa8fe6c..931f0c5 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -322,6 +322,78 @@
 InnerClasses:
   public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
   public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_1
+         x: newarray       int
+         x: dup
+         x: iconst_0
+         x: iconst_1
+         x: iastore
+         x: putstatic     #x                  // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+}
+SourceFile: "R.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+}
+SourceFile: "R.java"
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index c605f76..906a81c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -122,6 +122,100 @@
 NestMembers:
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 11d5939..10bc91d 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -348,6 +348,108 @@
 NestMembers:
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: iconst_1
+         x: newarray       int
+         x: dup
+         x: iconst_0
+         x: iconst_1
+         x: iastore
+         x: putstatic     #x                 // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: aload_0
+         x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index c605f76..906a81c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -122,6 +122,100 @@
 NestMembers:
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index 088bc80..fcf9a8c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -481,6 +481,136 @@
 NestMembers:
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
   com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy
+## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R$Nested
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R$Nested
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public static int[] ARRAY;
+    descriptor: [I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  public com.android.hoststubgen.test.tinyframework.R$Nested();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R$Nested;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R$Nested
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: iconst_1
+        x: newarray       int
+        x: dup
+        x: iconst_0
+        x: iconst_1
+        x: iastore
+        x: putstatic     #x                 // Field ARRAY:[I
+        x: return
+      LineNumberTable:
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;            // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/R.class
+  Compiled from "R.java"
+public class com.android.hoststubgen.test.tinyframework.R
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/R
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.R();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/R
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/R;
+    RuntimeVisibleAnnotations:
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+      x: #x()
+        com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+  public static #x= #x of #x;           // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+SourceFile: "R.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/R$Nested
 ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
   Compiled from "TinyFrameworkCallerCheck.java"
 class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
index d302084..696b6d0 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -19,6 +19,9 @@
 # Heuristics rule: Stub all the AIDL classes.
 class :aidl stubclass
 
+# Heuristics rule: Stub all the R classes.
+class :r stubclass
+
 # Default is "remove", so let's put all the base classes / interfaces in the stub first.
 class com.android.hoststubgen.test.tinyframework.subclasstest.C1 stub
 class com.android.hoststubgen.test.tinyframework.subclasstest.C2 stub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
new file mode 100644
index 0000000..b1bedf4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+public class R {
+    public static class Nested {
+        public static int[] ARRAY = new int[] {1};
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 762180d..37925e8 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -19,6 +19,7 @@
 
 import static org.junit.Assert.fail;
 
+import com.android.hoststubgen.test.tinyframework.R.Nested;
 import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass;
 
 import org.junit.Rule;
@@ -328,4 +329,9 @@
         assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2);
         assertThat(IPretendingAidl.Stub.Proxy.addTwo(1)).isEqualTo(3);
     }
+
+    @Test
+    public void testRFileHeuristics() {
+        assertThat(Nested.ARRAY.length).isEqualTo(1);
+    }
 }